summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/Android.bp2
-rw-r--r--core/api/current.txt14
-rw-r--r--core/java/android/app/ActivityThread.java12
-rw-r--r--core/java/android/app/Notification.java12
-rw-r--r--core/java/android/app/servertransaction/ClientTransactionListenerController.java11
-rw-r--r--core/java/android/audio/policy/configuration/V7_0/package-info.java23
-rw-r--r--core/java/android/companion/virtual/flags/flags.aconfig7
-rw-r--r--core/java/android/content/ContentProvider.java13
-rw-r--r--core/java/android/content/Intent.java2
-rw-r--r--core/java/android/content/IntentSender.java83
-rw-r--r--core/java/android/content/pm/ActivityInfo.java31
-rw-r--r--core/java/android/content/pm/ShortcutServiceInternal.java3
-rw-r--r--core/java/android/content/pm/multiuser.aconfig10
-rw-r--r--core/java/android/content/res/flags.aconfig10
-rw-r--r--core/java/android/hardware/OWNERS2
-rw-r--r--core/java/android/hardware/camera2/CameraManager.java20
-rw-r--r--core/java/android/hardware/devicestate/DeviceStateManager.java8
-rw-r--r--core/java/android/hardware/display/DisplayManager.java2
-rw-r--r--core/java/android/hardware/display/DisplayManagerInternal.java6
-rw-r--r--core/java/android/hardware/input/VirtualRotaryEncoderScrollEvent.java3
-rw-r--r--core/java/android/hardware/input/input_framework.aconfig7
-rw-r--r--core/java/android/inputmethodservice/ImsConfigurationTracker.java8
-rw-r--r--core/java/android/inputmethodservice/navigationbar/NavigationBarConstants.java9
-rw-r--r--core/java/android/inputmethodservice/navigationbar/NavigationBarView.java8
-rw-r--r--core/java/android/os/UserManager.java41
-rw-r--r--core/java/android/security/flags.aconfig7
-rw-r--r--core/java/android/service/chooser/flags.aconfig8
-rw-r--r--core/java/android/tracing/flags.aconfig8
-rw-r--r--core/java/android/view/IWindowManager.aidl8
-rw-r--r--core/java/android/view/InsetsFrameProvider.java6
-rw-r--r--core/java/android/view/KeyboardShortcutGroup.aidl3
-rw-r--r--core/java/android/view/KeyboardShortcutInfo.java19
-rw-r--r--core/java/android/view/SurfaceControlRegistry.java32
-rw-r--r--core/java/android/view/View.java94
-rw-r--r--core/java/android/view/ViewRootImpl.java23
-rw-r--r--core/java/android/view/WindowManager.java9
-rw-r--r--core/java/android/view/WindowManagerImpl.java10
-rw-r--r--core/java/android/view/inputmethod/InputMethodInfo.java6
-rw-r--r--core/java/android/view/inputmethod/flags.aconfig9
-rw-r--r--core/java/android/webkit/WebViewFactory.java9
-rw-r--r--core/java/android/window/BackProgressAnimator.java6
-rw-r--r--core/java/android/window/ITaskFragmentOrganizerController.aidl13
-rw-r--r--core/java/android/window/TaskFragmentOrganizer.java30
-rw-r--r--core/java/android/window/TransitionInfo.java2
-rw-r--r--core/java/android/window/TransitionRequestInfo.java2
-rw-r--r--core/java/android/window/WindowContainerTransaction.java7
-rw-r--r--core/java/android/window/WindowOnBackInvokedDispatcher.java1
-rw-r--r--core/java/android/window/flags/lse_desktop_experience.aconfig25
-rw-r--r--core/java/android/window/flags/windowing_frontend.aconfig26
-rw-r--r--core/java/com/android/internal/app/SuspendedAppActivity.java4
-rw-r--r--core/java/com/android/internal/jank/Cuj.java41
-rw-r--r--core/java/com/android/internal/os/flags.aconfig2
-rw-r--r--core/java/com/android/internal/pm/pkg/component/AconfigFlags.java23
-rw-r--r--core/java/com/android/internal/policy/DecorView.java19
-rw-r--r--core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java299
-rw-r--r--core/java/com/android/internal/protolog/ProtoLogViewerConfigReader.java122
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtils.java10
-rw-r--r--core/jni/android_media_AudioSystem.cpp5
-rw-r--r--core/proto/android/server/inputmethod/inputmethodmanagerservice.proto3
-rw-r--r--core/res/res/values-af/strings.xml26
-rw-r--r--core/res/res/values-am/strings.xml26
-rw-r--r--core/res/res/values-ar/strings.xml19
-rw-r--r--core/res/res/values-as/strings.xml17
-rw-r--r--core/res/res/values-az/strings.xml26
-rw-r--r--core/res/res/values-b+sr+Latn/strings.xml26
-rw-r--r--core/res/res/values-be/strings.xml17
-rw-r--r--core/res/res/values-bg/strings.xml26
-rw-r--r--core/res/res/values-bn/strings.xml26
-rw-r--r--core/res/res/values-bs/strings.xml26
-rw-r--r--core/res/res/values-ca/strings.xml26
-rw-r--r--core/res/res/values-cs/strings.xml28
-rw-r--r--core/res/res/values-da/strings.xml28
-rw-r--r--core/res/res/values-de/strings.xml28
-rw-r--r--core/res/res/values-el/strings.xml28
-rw-r--r--core/res/res/values-en-rAU/strings.xml26
-rw-r--r--core/res/res/values-en-rCA/strings.xml17
-rw-r--r--core/res/res/values-en-rGB/strings.xml26
-rw-r--r--core/res/res/values-en-rIN/strings.xml26
-rw-r--r--core/res/res/values-en-rXC/strings.xml17
-rw-r--r--core/res/res/values-es-rUS/strings.xml26
-rw-r--r--core/res/res/values-es/strings.xml28
-rw-r--r--core/res/res/values-et/strings.xml26
-rw-r--r--core/res/res/values-eu/strings.xml28
-rw-r--r--core/res/res/values-fa/strings.xml28
-rw-r--r--core/res/res/values-fi/strings.xml26
-rw-r--r--core/res/res/values-fr-rCA/strings.xml656
-rw-r--r--core/res/res/values-fr/strings.xml26
-rw-r--r--core/res/res/values-gl/strings.xml26
-rw-r--r--core/res/res/values-gu/strings.xml26
-rw-r--r--core/res/res/values-hi/strings.xml23
-rw-r--r--core/res/res/values-hr/strings.xml26
-rw-r--r--core/res/res/values-hu/strings.xml26
-rw-r--r--core/res/res/values-hy/strings.xml26
-rw-r--r--core/res/res/values-in/strings.xml26
-rw-r--r--core/res/res/values-is/strings.xml26
-rw-r--r--core/res/res/values-it/strings.xml17
-rw-r--r--core/res/res/values-iw/strings.xml17
-rw-r--r--core/res/res/values-ja/strings.xml17
-rw-r--r--core/res/res/values-ka/strings.xml17
-rw-r--r--core/res/res/values-kk/strings.xml26
-rw-r--r--core/res/res/values-km/strings.xml26
-rw-r--r--core/res/res/values-kn/strings.xml17
-rw-r--r--core/res/res/values-ko/strings.xml28
-rw-r--r--core/res/res/values-ky/strings.xml26
-rw-r--r--core/res/res/values-lo/strings.xml26
-rw-r--r--core/res/res/values-lt/strings.xml26
-rw-r--r--core/res/res/values-lv/strings.xml26
-rw-r--r--core/res/res/values-mk/strings.xml26
-rw-r--r--core/res/res/values-ml/strings.xml26
-rw-r--r--core/res/res/values-mn/strings.xml26
-rw-r--r--core/res/res/values-mr/strings.xml17
-rw-r--r--core/res/res/values-ms/strings.xml19
-rw-r--r--core/res/res/values-my/strings.xml17
-rw-r--r--core/res/res/values-nb/strings.xml30
-rw-r--r--core/res/res/values-ne/strings.xml17
-rw-r--r--core/res/res/values-nl/strings.xml26
-rw-r--r--core/res/res/values-or/strings.xml26
-rw-r--r--core/res/res/values-pa/strings.xml26
-rw-r--r--core/res/res/values-pl/strings.xml17
-rw-r--r--core/res/res/values-pt-rBR/strings.xml17
-rw-r--r--core/res/res/values-pt-rPT/strings.xml21
-rw-r--r--core/res/res/values-pt/strings.xml17
-rw-r--r--core/res/res/values-ro/strings.xml26
-rw-r--r--core/res/res/values-ru/strings.xml26
-rw-r--r--core/res/res/values-si/strings.xml26
-rw-r--r--core/res/res/values-sk/strings.xml30
-rw-r--r--core/res/res/values-sl/strings.xml26
-rw-r--r--core/res/res/values-sq/strings.xml26
-rw-r--r--core/res/res/values-sr/strings.xml26
-rw-r--r--core/res/res/values-sv/strings.xml26
-rw-r--r--core/res/res/values-sw/strings.xml26
-rw-r--r--core/res/res/values-ta/strings.xml26
-rw-r--r--core/res/res/values-te/strings.xml17
-rw-r--r--core/res/res/values-th/strings.xml26
-rw-r--r--core/res/res/values-tl/strings.xml26
-rw-r--r--core/res/res/values-tr/strings.xml26
-rw-r--r--core/res/res/values-uk/strings.xml26
-rw-r--r--core/res/res/values-ur/strings.xml26
-rw-r--r--core/res/res/values-uz/strings.xml17
-rw-r--r--core/res/res/values-vi/strings.xml28
-rw-r--r--core/res/res/values-zh-rCN/strings.xml26
-rw-r--r--core/res/res/values-zh-rHK/strings.xml17
-rw-r--r--core/res/res/values-zh-rTW/strings.xml30
-rw-r--r--core/res/res/values-zu/strings.xml26
-rw-r--r--core/res/res/values/attrs.xml2
-rw-r--r--core/res/res/values/attrs_manifest.xml13
-rw-r--r--core/res/res/values/public-staging.xml2
-rw-r--r--core/res/res/values/strings.xml19
-rw-r--r--core/res/res/values/symbols.xml11
-rw-r--r--core/res/res/xml/power_profile.xml6
-rw-r--r--core/tests/InputMethodCoreTests/src/android/view/inputmethod/InputMethodInfoTest.java2
-rw-r--r--core/tests/coretests/src/android/app/activity/ActivityThreadTest.java5
-rw-r--r--core/tests/coretests/src/android/app/servertransaction/ClientTransactionListenerControllerTest.java4
-rw-r--r--core/tests/coretests/src/android/inputmethodservice/ImsConfigurationTrackerTest.java30
-rw-r--r--core/tests/coretests/src/android/view/ViewFrameRateTest.java117
-rw-r--r--core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java4
-rw-r--r--core/tests/overlaytests/handle_config_change/Android.bp45
-rw-r--r--core/tests/overlaytests/handle_config_change/AndroidTest.xml35
-rw-r--r--core/tests/overlaytests/handle_config_change/src/com/android/overlaytest/HandleConfigChangeHostTests.java47
-rw-r--r--core/tests/overlaytests/handle_config_change/test-apps/OverlayResApp/Android.bp43
-rw-r--r--core/tests/overlaytests/handle_config_change/test-apps/OverlayResApp/AndroidManifest.xml33
-rw-r--r--core/tests/overlaytests/handle_config_change/test-apps/OverlayResApp/res/values/integers.xml20
-rw-r--r--core/tests/overlaytests/handle_config_change/test-apps/OverlayResApp/res/values/strings.xml21
-rw-r--r--core/tests/overlaytests/handle_config_change/test-apps/OverlayResApp/src/com/android/overlaytest/overlayresapp/OverlayResActivity.java50
-rw-r--r--core/tests/overlaytests/handle_config_change/test-apps/OverlayResApp/src/com/android/overlaytest/overlayresapp/OverlayResTest.java148
-rw-r--r--core/tests/resourceflaggingtests/OWNERS1
-rw-r--r--data/etc/OWNERS1
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java23
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java23
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java5
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationAdapter.java224
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationController.java79
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java309
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationSpec.java267
-rw-r--r--libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java20
-rw-r--r--libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java8
-rw-r--r--libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentAnimationControllerTest.java88
-rw-r--r--libs/WindowManager/Shell/Android.bp1
-rw-r--r--libs/WindowManager/Shell/aconfig/multitasking.aconfig10
-rw-r--r--libs/WindowManager/Shell/multivalentScreenshotTests/goldens/robolectric/phone/dark_portrait_bubbles_education.pngbin56309 -> 56741 bytes
-rw-r--r--libs/WindowManager/Shell/multivalentScreenshotTests/goldens/robolectric/phone/light_portrait_bubbles_education.pngbin56309 -> 56741 bytes
-rw-r--r--libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml12
-rw-r--r--libs/WindowManager/Shell/res/values-fa/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-fr-rCA/strings.xml28
-rw-r--r--libs/WindowManager/Shell/res/values-nb/strings.xml2
-rw-r--r--libs/WindowManager/Shell/res/values/dimen.xml16
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java7
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/HandlerExecutor.java7
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/ShellExecutor.java7
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1Module.java28
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java10
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/PipModule.java17
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt41
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/docs/debugging.md6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java7
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragUtils.java47
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java12
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java97
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java20
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java37
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTaskController.java3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java17
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java43
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java52
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java106
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java68
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java25
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometry.java37
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.java539
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt484
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenuAnimator.kt10
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java13
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/additionalviewcontainer/AdditionalSystemViewContainer.kt9
-rw-r--r--libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/desktopmode/scenarios/ExitDesktopWithDragToTopDragZone.kt68
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt232
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/DefaultTransitionHandlerTest.java74
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/TransitionAnimationHelperTest.kt126
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/CaptionWindowDecorationTests.kt107
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometryTests.java38
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/HandleMenuTest.kt77
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java53
-rw-r--r--libs/hwui/Android.bp10
-rw-r--r--libs/hwui/apex/LayoutlibLoader.cpp21
-rw-r--r--libs/hwui/hwui/DrawTextFunctor.h13
-rw-r--r--libs/hwui/jni/MeshSpecification.cpp2
-rw-r--r--libs/hwui/jni/android_graphics_HardwareBufferRenderer.cpp2
-rw-r--r--location/Android.bp3
-rw-r--r--location/java/com/android/internal/location/package-info.java22
-rw-r--r--media/java/android/media/AudioTrack.java1
-rw-r--r--media/tests/mediatestutils/java/com/android/media/mediatestutils/TestUtils.java77
-rw-r--r--nfc/Android.bp3
-rw-r--r--nfc/java/android/nfc/INfcAdapter.aidl1
-rw-r--r--nfc/java/android/nfc/NfcAdapter.java465
-rw-r--r--packages/CarrierDefaultApp/res/values-fr-rCA/strings.xml2
-rw-r--r--packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml34
-rw-r--r--packages/CrashRecovery/aconfig/flags.aconfig8
-rw-r--r--packages/CredentialManager/res/values-el/strings.xml2
-rw-r--r--packages/CredentialManager/res/values-fr-rCA/strings.xml4
-rw-r--r--packages/CredentialManager/res/values-pa/strings.xml2
-rw-r--r--packages/CredentialManager/wear/res/values-am/strings.xml34
-rw-r--r--packages/CredentialManager/wear/res/values-as/strings.xml34
-rw-r--r--packages/CredentialManager/wear/res/values-cs/strings.xml34
-rw-r--r--packages/CredentialManager/wear/res/values-el/strings.xml34
-rw-r--r--packages/CredentialManager/wear/res/values-en-rAU/strings.xml34
-rw-r--r--packages/CredentialManager/wear/res/values-en-rCA/strings.xml34
-rw-r--r--packages/CredentialManager/wear/res/values-en-rGB/strings.xml34
-rw-r--r--packages/CredentialManager/wear/res/values-en-rIN/strings.xml34
-rw-r--r--packages/CredentialManager/wear/res/values-en-rXC/strings.xml34
-rw-r--r--packages/CredentialManager/wear/res/values-es-rUS/strings.xml34
-rw-r--r--packages/CredentialManager/wear/res/values-fi/strings.xml34
-rw-r--r--packages/CredentialManager/wear/res/values-gu/strings.xml34
-rw-r--r--packages/CredentialManager/wear/res/values-hi/strings.xml34
-rw-r--r--packages/CredentialManager/wear/res/values-hy/strings.xml34
-rw-r--r--packages/CredentialManager/wear/res/values-is/strings.xml34
-rw-r--r--packages/CredentialManager/wear/res/values-ja/strings.xml34
-rw-r--r--packages/CredentialManager/wear/res/values-ka/strings.xml34
-rw-r--r--packages/CredentialManager/wear/res/values-km/strings.xml34
-rw-r--r--packages/CredentialManager/wear/res/values-kn/strings.xml34
-rw-r--r--packages/CredentialManager/wear/res/values-ko/strings.xml34
-rw-r--r--packages/CredentialManager/wear/res/values-lo/strings.xml34
-rw-r--r--packages/CredentialManager/wear/res/values-ml/strings.xml34
-rw-r--r--packages/CredentialManager/wear/res/values-mr/strings.xml34
-rw-r--r--packages/CredentialManager/wear/res/values-ms/strings.xml34
-rw-r--r--packages/CredentialManager/wear/res/values-my/strings.xml34
-rw-r--r--packages/CredentialManager/wear/res/values-nb/strings.xml34
-rw-r--r--packages/CredentialManager/wear/res/values-nl/strings.xml34
-rw-r--r--packages/CredentialManager/wear/res/values-pt-rPT/strings.xml34
-rw-r--r--packages/CredentialManager/wear/res/values-sl/strings.xml34
-rw-r--r--packages/CredentialManager/wear/res/values-sw/strings.xml34
-rw-r--r--packages/CredentialManager/wear/res/values-ta/strings.xml34
-rw-r--r--packages/CredentialManager/wear/res/values-te/strings.xml34
-rw-r--r--packages/CredentialManager/wear/res/values-th/strings.xml34
-rw-r--r--packages/CredentialManager/wear/res/values-tl/strings.xml34
-rw-r--r--packages/CredentialManager/wear/res/values-ur/strings.xml34
-rw-r--r--packages/CredentialManager/wear/res/values-uz/strings.xml34
-rw-r--r--packages/CredentialManager/wear/res/values-vi/strings.xml34
-rw-r--r--packages/CredentialManager/wear/res/values-zh-rHK/strings.xml34
-rw-r--r--packages/PackageInstaller/res/values-fr-rCA/strings.xml110
-rw-r--r--packages/PackageInstaller/src/com/android/packageinstaller/v2/model/InstallRepository.kt29
-rw-r--r--packages/PackageInstaller/src/com/android/packageinstaller/v2/model/PackageUtil.kt4
-rw-r--r--packages/PrintSpooler/res/values-fr-rCA/strings.xml2
-rw-r--r--packages/SettingsLib/AppPreference/res/values-fr-rCA/strings.xml2
-rw-r--r--packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java10
-rw-r--r--packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/DebugActivity.kt23
-rw-r--r--packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/DebugFormat.kt1
-rw-r--r--packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/search/SpaSearchContract.kt5
-rw-r--r--packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/search/SpaSearchProvider.kt12
-rw-r--r--packages/SettingsLib/SpaPrivileged/res/values-fr-rCA/strings.xml2
-rw-r--r--packages/SettingsLib/res/layout/zen_mode_duration_dialog.xml4
-rw-r--r--packages/SettingsLib/res/values-af/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-am/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-ar/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-as/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-az/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-b+sr+Latn/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-be/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-bg/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-bn/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-bs/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-ca/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-cs/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-da/arrays.xml4
-rw-r--r--packages/SettingsLib/res/values-da/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-de/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-el/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-en-rAU/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-en-rCA/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-en-rGB/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-en-rIN/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-en-rXC/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-es-rUS/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-es/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-et/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-eu/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-fa/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-fi/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-fr-rCA/strings.xml84
-rw-r--r--packages/SettingsLib/res/values-fr/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-gl/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-gu/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-hi/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-hr/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-hu/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-hy/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-in/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-is/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-it/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-iw/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-ja/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-ka/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-kk/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-km/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-kn/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-ko/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-ky/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-lo/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-lt/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-lv/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-mk/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-ml/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-mn/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-mr/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-ms/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-my/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-nb/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-ne/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-nl/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-or/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-pa/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-pl/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-pt-rBR/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-pt-rPT/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-pt/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-ro/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-ru/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-si/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-sk/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-sl/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-sq/strings.xml6
-rw-r--r--packages/SettingsLib/res/values-sr/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-sv/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-sw/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-ta/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-te/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-th/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-tl/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-tr/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-uk/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-ur/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-uz/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-vi/strings.xml6
-rw-r--r--packages/SettingsLib/res/values-zh-rCN/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-zh-rHK/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-zh-rTW/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-zu/strings.xml4
-rw-r--r--packages/SettingsLib/res/values/colors.xml7
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/graph/SignalDrawable.java4
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/media/RouterInfoMediaManager.java23
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/mobile/dataservice/DataServiceUtils.java88
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/mobile/dataservice/SubscriptionInfoDao.java9
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/mobile/dataservice/SubscriptionInfoEntity.java136
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/notification/data/repository/ZenModeRepository.kt9
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenMode.java6
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/data/repository/ZenModeRepositoryTest.kt16
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/modes/ZenModeTest.java2
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java28
-rw-r--r--packages/Shell/res/values-fr-rCA/strings.xml2
-rw-r--r--packages/Shell/res/values-nb/strings.xml2
-rw-r--r--packages/SimAppDialog/res/values-fr-rCA/strings.xml6
-rw-r--r--packages/SystemUI/Android.bp9
-rw-r--r--packages/SystemUI/accessibility/accessibilitymenu/res/values-bn/strings.xml2
-rw-r--r--packages/SystemUI/accessibility/accessibilitymenu/res/values-fr-rCA/strings.xml2
-rw-r--r--packages/SystemUI/accessibility/accessibilitymenu/res/values-hi/strings.xml2
-rw-r--r--packages/SystemUI/accessibility/accessibilitymenu/res/values-hr/strings.xml4
-rw-r--r--packages/SystemUI/accessibility/accessibilitymenu/res/values-nb/strings.xml2
-rw-r--r--packages/SystemUI/accessibility/accessibilitymenu/res/values-nl/strings.xml2
-rw-r--r--packages/SystemUI/accessibility/accessibilitymenu/res/values-sk/strings.xml4
-rw-r--r--packages/SystemUI/aconfig/systemui.aconfig43
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt24
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt23
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt7
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ShortcutsBesideUdfpsBlueprint.kt7
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/NotificationSection.kt8
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/StatusBarSection.kt38
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt25
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaCarousel.kt75
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaScenePicker.kt72
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt27
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/statusbar/ui/composable/StatusBar.kt43
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt81
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/PredictiveBackHandler.kt17
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/PunchHole.kt178
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt51
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt107
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt52
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ObservableTransitionStateTest.kt19
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/PredictiveBackHandlerTest.kt159
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt147
-rw-r--r--packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/TestSceneScope.kt10
-rw-r--r--packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/TestTransition.kt56
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt2
-rw-r--r--packages/SystemUI/lint-baseline.xml33
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalBackupRestoreStartableTest.kt81
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalOngoingContentStartableTest.kt89
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt23
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/db/DefaultWidgetPopulationTest.kt157
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalMediaRepositoryImplTest.kt35
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalSmartspaceRepositoryImplTest.kt319
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryImplTest.kt259
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt71
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractorTest.kt126
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt41
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt74
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt19
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/qs/QSLongPressEffectTest.kt106
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractorTest.kt64
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractorTest.kt39
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModelTest.kt25
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt9
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModelTest.kt67
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/SettingObserverTest.kt117
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/data/repository/QSPreferencesRepositoryTest.kt78
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/domain/interactor/GridConsistencyInteractorTest.kt27
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/domain/interactor/IconTilesInteractorTest.kt86
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/domain/interactor/InfiniteGridConsistencyInteractorTest.kt26
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/InfiniteGridLayoutTest.kt12
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/PartitionedGridLayoutTest.kt12
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/QuickQuickSettingsViewModelTest.kt27
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/airplane/domain/interactor/AirplaneModeTileDataInteractorTest.kt (renamed from packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/airplate/domain/interactor/AirplaneModeTileDataInteractorTest.kt)3
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/airplane/domain/interactor/AirplaneModeTileUserActionInteractorTest.kt (renamed from packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/airplate/domain/interactor/AirplaneModeTileUserActionInteractorTest.kt)5
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractorTest.kt92
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/reducebrightness/domain/interactor/ReduceBrightColorsTileDataInteractorTest.kt4
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/reducebrightness/domain/interactor/ReduceBrightColorsTileUserActionInteractorTest.kt72
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/adapter/QSSceneAdapterImplTest.kt5
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt4
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt2
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/GoneSceneViewModelTest.kt5
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImplTest.kt45
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImplTest.kt18
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt14
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationInteractorTest.kt59
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractorTest.kt5
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.java243
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.kt232
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialog.java1
-rw-r--r--packages/SystemUI/res-product/values-fr-rCA/strings.xml6
-rw-r--r--packages/SystemUI/res/layout/app_clips_screenshot.xml2
-rw-r--r--packages/SystemUI/res/layout/clipboard_overlay.xml32
-rw-r--r--packages/SystemUI/res/layout/clipboard_overlay2.xml202
-rw-r--r--packages/SystemUI/res/layout/keyboard_shortcuts_search_view.xml2
-rw-r--r--packages/SystemUI/res/layout/screenshot.xml40
-rw-r--r--packages/SystemUI/res/layout/window_magnification_settings_view.xml8
-rw-r--r--packages/SystemUI/res/values-af/strings.xml29
-rw-r--r--packages/SystemUI/res/values-am/strings.xml11
-rw-r--r--packages/SystemUI/res/values-ar/strings.xml7
-rw-r--r--packages/SystemUI/res/values-as/strings.xml5
-rw-r--r--packages/SystemUI/res/values-az/strings.xml11
-rw-r--r--packages/SystemUI/res/values-b+sr+Latn/strings.xml11
-rw-r--r--packages/SystemUI/res/values-be/strings.xml5
-rw-r--r--packages/SystemUI/res/values-bg/strings.xml11
-rw-r--r--packages/SystemUI/res/values-bn/strings.xml11
-rw-r--r--packages/SystemUI/res/values-bs/strings.xml11
-rw-r--r--packages/SystemUI/res/values-ca/strings.xml11
-rw-r--r--packages/SystemUI/res/values-cs/strings.xml11
-rw-r--r--packages/SystemUI/res/values-da/strings.xml11
-rw-r--r--packages/SystemUI/res/values-de/strings.xml11
-rw-r--r--packages/SystemUI/res/values-el/strings.xml11
-rw-r--r--packages/SystemUI/res/values-en-rAU/strings.xml11
-rw-r--r--packages/SystemUI/res/values-en-rCA/strings.xml5
-rw-r--r--packages/SystemUI/res/values-en-rGB/strings.xml11
-rw-r--r--packages/SystemUI/res/values-en-rIN/strings.xml11
-rw-r--r--packages/SystemUI/res/values-en-rXC/strings.xml5
-rw-r--r--packages/SystemUI/res/values-es-rUS/strings.xml29
-rw-r--r--packages/SystemUI/res/values-es/strings.xml11
-rw-r--r--packages/SystemUI/res/values-et/strings.xml11
-rw-r--r--packages/SystemUI/res/values-eu/strings.xml11
-rw-r--r--packages/SystemUI/res/values-fa/strings.xml11
-rw-r--r--packages/SystemUI/res/values-fi/strings.xml11
-rw-r--r--packages/SystemUI/res/values-fr-rCA-ldrtl/strings.xml2
-rw-r--r--packages/SystemUI/res/values-fr-rCA/strings.xml207
-rw-r--r--packages/SystemUI/res/values-fr/strings.xml11
-rw-r--r--packages/SystemUI/res/values-gl/strings.xml11
-rw-r--r--packages/SystemUI/res/values-gu/strings.xml11
-rw-r--r--packages/SystemUI/res/values-hi/strings.xml5
-rw-r--r--packages/SystemUI/res/values-hr/strings.xml11
-rw-r--r--packages/SystemUI/res/values-hu/strings.xml29
-rw-r--r--packages/SystemUI/res/values-hy/strings.xml11
-rw-r--r--packages/SystemUI/res/values-in/strings.xml11
-rw-r--r--packages/SystemUI/res/values-is/strings.xml13
-rw-r--r--packages/SystemUI/res/values-it/strings.xml5
-rw-r--r--packages/SystemUI/res/values-iw/strings.xml5
-rw-r--r--packages/SystemUI/res/values-ja/strings.xml5
-rw-r--r--packages/SystemUI/res/values-ka/strings.xml5
-rw-r--r--packages/SystemUI/res/values-kk/strings.xml11
-rw-r--r--packages/SystemUI/res/values-km/strings.xml11
-rw-r--r--packages/SystemUI/res/values-kn/strings.xml5
-rw-r--r--packages/SystemUI/res/values-kn/tiles_states_strings.xml2
-rw-r--r--packages/SystemUI/res/values-ko/strings.xml15
-rw-r--r--packages/SystemUI/res/values-ky/strings.xml11
-rw-r--r--packages/SystemUI/res/values-lo/strings.xml11
-rw-r--r--packages/SystemUI/res/values-lt/strings.xml11
-rw-r--r--packages/SystemUI/res/values-lv/strings.xml13
-rw-r--r--packages/SystemUI/res/values-mk/strings.xml29
-rw-r--r--packages/SystemUI/res/values-ml/strings.xml11
-rw-r--r--packages/SystemUI/res/values-mn/strings.xml11
-rw-r--r--packages/SystemUI/res/values-mr/strings.xml5
-rw-r--r--packages/SystemUI/res/values-ms/strings.xml5
-rw-r--r--packages/SystemUI/res/values-my/strings.xml5
-rw-r--r--packages/SystemUI/res/values-nb/strings.xml13
-rw-r--r--packages/SystemUI/res/values-ne/strings.xml5
-rw-r--r--packages/SystemUI/res/values-nl/strings.xml11
-rw-r--r--packages/SystemUI/res/values-or/strings.xml11
-rw-r--r--packages/SystemUI/res/values-pa/strings.xml11
-rw-r--r--packages/SystemUI/res/values-pl/strings.xml5
-rw-r--r--packages/SystemUI/res/values-pt-rBR/strings.xml5
-rw-r--r--packages/SystemUI/res/values-pt-rPT/strings.xml5
-rw-r--r--packages/SystemUI/res/values-pt/strings.xml5
-rw-r--r--packages/SystemUI/res/values-ro/strings.xml11
-rw-r--r--packages/SystemUI/res/values-ru/strings.xml11
-rw-r--r--packages/SystemUI/res/values-si/strings.xml11
-rw-r--r--packages/SystemUI/res/values-sk/strings.xml11
-rw-r--r--packages/SystemUI/res/values-sl/strings.xml11
-rw-r--r--packages/SystemUI/res/values-sq/strings.xml29
-rw-r--r--packages/SystemUI/res/values-sr/strings.xml11
-rw-r--r--packages/SystemUI/res/values-sv/strings.xml11
-rw-r--r--packages/SystemUI/res/values-sw/strings.xml11
-rw-r--r--packages/SystemUI/res/values-ta/strings.xml11
-rw-r--r--packages/SystemUI/res/values-te/strings.xml5
-rw-r--r--packages/SystemUI/res/values-th/strings.xml11
-rw-r--r--packages/SystemUI/res/values-tl/strings.xml11
-rw-r--r--packages/SystemUI/res/values-tr/strings.xml11
-rw-r--r--packages/SystemUI/res/values-uk/strings.xml29
-rw-r--r--packages/SystemUI/res/values-ur/strings.xml11
-rw-r--r--packages/SystemUI/res/values-uz/strings.xml5
-rw-r--r--packages/SystemUI/res/values-vi/strings.xml11
-rw-r--r--packages/SystemUI/res/values-zh-rCN/strings.xml11
-rw-r--r--packages/SystemUI/res/values-zh-rHK/strings.xml5
-rw-r--r--packages/SystemUI/res/values-zh-rTW/strings.xml11
-rw-r--r--packages/SystemUI/res/values-zu/strings.xml11
-rw-r--r--packages/SystemUI/res/values/colors.xml4
-rw-r--r--packages/SystemUI/res/values/config.xml4
-rw-r--r--packages/SystemUI/res/values/dimens.xml1
-rw-r--r--packages/SystemUI/res/values/strings.xml12
-rw-r--r--packages/SystemUI/res/values/styles.xml11
-rw-r--r--packages/SystemUI/res/values/tiles_states_strings.xml10
-rw-r--r--packages/SystemUI/res/xml/large_screen_shade_header.xml1
-rw-r--r--packages/SystemUI/schemas/com.android.systemui.communal.data.db.CommunalDatabase/2.json81
-rw-r--r--packages/SystemUI/src/com/android/systemui/Dependency.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/MagnificationSettingsController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java26
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java23
-rw-r--r--packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractor.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayView.java106
-rw-r--r--packages/SystemUI/src/com/android/systemui/clipboardoverlay/dagger/ClipboardOverlayModule.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/CommunalBackupRestoreStartable.kt58
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/CommunalOngoingContentStartable.kt62
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt32
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalModule.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalStartableModule.kt62
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/data/backup/CommunalBackupUtils.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/data/db/CommunalDatabase.kt27
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/data/db/CommunalEntities.kt23
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/data/db/CommunalWidgetDao.kt106
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/data/model/CommunalSmartspaceTimer.kt29
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalMediaRepository.kt53
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSmartspaceRepository.kt123
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSmartspaceRepositoryModule.kt (renamed from packages/SystemUI/src/com/android/systemui/smartspace/data/repository/SmartspaceRepositoryModule.kt)11
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalWidgetRepository.kt85
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt71
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractor.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/proto/communal_hub_state.proto3
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt34
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt14
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalWidgetModule.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java29
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt98
-rw-r--r--packages/SystemUI/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepository.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt18
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeHost.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeUi.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/homecontrols/TaskFragmentComponent.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffect.kt52
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ShortcutHelperModule.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperCategoriesRepository.kt134
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperKeys.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/CurrentAppShortcutsSource.kt34
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/InputShortcutsSource.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractor.kt11
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shortcut/qualifiers/CurrentAppShortcuts.kt (renamed from packages/SystemUI/src/com/android/systemui/qs/panels/shared/model/IconLabelVisibilityLog.kt)7
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutCategory.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt93
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/model/IconSource.kt22
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModel.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt14
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java23
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ResourceTrimmer.kt21
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt46
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt32
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractor.kt13
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractor.kt36
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardEnabledInteractor.kt14
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardOcclusionInteractor.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractor.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardWakeDirectlyToGoneInteractor.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardState.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlows.kt19
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToGlanceableHubTransitionViewModel.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt22
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModel.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGlanceableHubTransitionViewModel.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/dagger/MediaLog.kt (renamed from packages/SystemUI/src/com/android/systemui/log/dagger/MediaLoadingLog.kt)7
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilterImpl.kt32
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/shared/MediaLogger.kt (renamed from packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaLoadingLogger.kt)44
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt31
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModel.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/people/widget/PeopleBackupHelper.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java74
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/ReduceBrightColorsController.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/ReduceBrightColorsControllerImpl.java29
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/SettingObserver.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/dagger/PanelsModule.kt25
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/DefaultLargeTilesRepository.kt (renamed from packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/IconTilesRepository.kt)29
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/QSPreferencesRepository.kt27
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/StockTilesRepository.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/GridConsistencyInteractor.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/IconLabelVisibilityInteractor.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/IconTilesInteractor.kt50
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/QSPreferencesInteractor.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/shared/model/PanelsLog.kt (renamed from packages/SystemUI/src/com/android/systemui/qs/panels/shared/model/GridConsistencyLog.kt)5
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/DragAndDropState.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/InfiniteGridLayout.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PartitionedGridLayout.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/StretchedGridLayout.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/Tile.kt38
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/IconTilesViewModel.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/QuickQuickSettingsViewModel.kt26
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/TileUiState.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/TileViewModel.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/ReduceBrightColorsAutoAddable.kt13
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tileimpl/SubtitleArrayMapping.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java34
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegate.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractor.kt46
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileUserActionInteractor.kt39
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/model/ModesTileModel.kt18
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/ui/ModesTileMapper.kt59
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/impl/reducebrightness/domain/interactor/ReduceBrightColorsTileDataInteractor.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/impl/reducebrightness/domain/interactor/ReduceBrightColorsTileUserActionInteractor.kt23
-rw-r--r--packages/SystemUI/src/com/android/systemui/recordissue/RecordIssueDialogDelegate.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/recordissue/TraceurMessageSender.kt39
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ActionExecutor.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/LegacyScreenshotViewProxy.kt242
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/MessageContainerController.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java223
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotShelfViewProxy.kt70
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java1126
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotViewProxy.kt76
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotExecutor.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsViewModel.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/dagger/ScreenshotModule.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeRepository.kt28
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt20
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorEmptyImpl.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt24
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorLegacyImpl.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImpl.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/domain/startable/ShadeStartable.kt24
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/shared/model/ShadeMode.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/smartspace/dagger/SmartspaceModule.kt32
-rw-r--r--packages/SystemUI/src/com/android/systemui/smartspace/data/repository/SmartspaceRepository.kt77
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java168
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java138
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/domain/interactor/StatusBarKeyguardViewManagerInteractor.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/VisualStabilityProvider.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationInteractor.kt90
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RichOngoingNotificationContentExtractor.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ExpandableViewState.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java43
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java21
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/ui/viewbinder/HeadsUpNotificationViewBinder.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/DarkIconDispatcherImpl.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java42
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java37
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/LetterboxAppearanceCalculator.kt37
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/AvalancheController.kt19
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/PolicyModule.kt51
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/SplitShadeStateController.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/TunablePadding.java104
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/ConvenienceExtensions.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/kotlin/ReduceBrightColorsControllerExt.kt14
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.kt83
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/settings/UserSettingsProxy.kt19
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/CsdWarningDialog.java149
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java16
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/accessibility/TestableWindowManager.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegateTest.java133
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/communal/data/backup/CommunalBackupHelperTest.kt23
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/communal/data/backup/CommunalBackupUtilsTest.kt35
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/communal/data/db/CommunalDatabaseMigrationsTest.kt149
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/communal/data/db/CommunalWidgetDaoTest.kt38
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt22
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperCategoriesRepositoryTest.kt90
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractorTest.kt23
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/ui/ShortcutHelperActivityStarterTest.kt59
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModelTest.kt22
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/ResourceTrimmerTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorTest.kt7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt1
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardWakeDirectlyToGoneInteractorTest.kt8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSectionTest.kt29
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelTest.kt19
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilterImplTest.kt103
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/navigationbar/views/NavigationBarTransitionsTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileViewImplTest.kt22
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotExecutorTest.kt12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsViewModelTest.java12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt45
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyboardShortcutListSearchTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyboardShortcutsTest.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java15
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt22
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt32
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModelTest.kt3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/touchpad/tutorial/ui/gesture/BackGestureMonitorTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/touchpad/tutorial/ui/gesture/TouchpadGestureHandlerTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/tuner/TunablePaddingTest.java126
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/settings/SettingsProxyTest.kt159
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/settings/UserSettingsProxyTest.kt259
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/volume/CsdWarningDialogTest.java106
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java16
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/TestMocksModule.kt4
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/accessibility/FakeReduceBrightColorsController.kt18
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/db/DefaultWidgetPopulationKosmos.kt (renamed from packages/SystemUI/tests/utils/src/com/android/systemui/smartspace/data/repository/SmartspaceRepositoryKosmos.kt)9
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/CommunalSmartspaceRepositoryKosmos.kt24
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalMediaRepository.kt14
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalSmartspaceRepository.kt45
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt14
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/haptics/qs/QSLongPressEffectKosmos.kt3
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/KeyboardShortcutHelperKosmos.kt11
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperTestHelper.kt3
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractorKosmos.kt4
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorKosmos.kt5
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorKosmos.kt2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilterKosmos.kt3
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/shared/MediaLoggerKosmos.kt (renamed from packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/MediaLoadingLoggerKosmos.kt)7
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModelKosmos.kt2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/DefaultLargeTilesRepositoryKosmos.kt (renamed from packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/IconTilesRepositoryKosmos.kt)3
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/QSPreferencesRepositoryKosmos.kt9
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/IconTilesInteractorKosmos.kt14
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/FakeShadeRepository.kt49
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeInteractorKosmos.kt1
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/smartspace/data/repository/FakeSmartspaceRepository.kt21
-rw-r--r--packages/VpnDialogs/res/values-fr-rCA/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-fr-rCA/strings.xml2
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java4
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java2
-rw-r--r--services/accessibility/java/com/android/server/accessibility/MouseKeysInterceptor.java199
-rw-r--r--services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java8
-rw-r--r--services/core/Android.bp1
-rw-r--r--services/core/java/com/android/server/TelephonyRegistry.java2
-rw-r--r--services/core/java/com/android/server/Watchdog.java1
-rw-r--r--services/core/java/com/android/server/accounts/AccountManagerService.java7
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java10
-rw-r--r--services/core/java/com/android/server/am/ApplicationThreadDeferred.java173
-rw-r--r--services/core/java/com/android/server/am/ApplicationThreadFilter.java603
-rw-r--r--services/core/java/com/android/server/am/CachedAppOptimizer.java5
-rw-r--r--services/core/java/com/android/server/am/ProcessRecord.java13
-rw-r--r--services/core/java/com/android/server/am/SettingsToPropertiesMapper.java1
-rw-r--r--services/core/java/com/android/server/am/flags.aconfig12
-rw-r--r--services/core/java/com/android/server/audio/BtHelper.java25
-rw-r--r--services/core/java/com/android/server/crashrecovery/CrashRecoveryModule.java54
-rw-r--r--services/core/java/com/android/server/crashrecovery/TEST_MAPPING3
-rw-r--r--services/core/java/com/android/server/display/BrightnessRangeController.java3
-rw-r--r--services/core/java/com/android/server/display/DisplayBrightnessState.java37
-rw-r--r--services/core/java/com/android/server/display/DisplayDeviceConfig.java206
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerService.java2
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerController.java15
-rw-r--r--services/core/java/com/android/server/display/HighBrightnessModeController.java2
-rw-r--r--services/core/java/com/android/server/display/LogicalDisplayMapper.java108
-rw-r--r--services/core/java/com/android/server/display/brightness/BrightnessUtils.java8
-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/HdrBrightnessModifier.java51
-rw-r--r--services/core/java/com/android/server/display/brightness/clamper/HdrClamper.java16
-rw-r--r--services/core/java/com/android/server/display/brightness/strategy/AutoBrightnessFallbackStrategy.java1
-rw-r--r--services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java1
-rw-r--r--services/core/java/com/android/server/display/brightness/strategy/BoostBrightnessStrategy.java1
-rw-r--r--services/core/java/com/android/server/display/brightness/strategy/DozeBrightnessStrategy.java1
-rw-r--r--services/core/java/com/android/server/display/brightness/strategy/FallbackBrightnessStrategy.java1
-rw-r--r--services/core/java/com/android/server/display/brightness/strategy/FollowerBrightnessStrategy.java2
-rw-r--r--services/core/java/com/android/server/display/brightness/strategy/InvalidBrightnessStrategy.java3
-rw-r--r--services/core/java/com/android/server/display/brightness/strategy/OffloadBrightnessStrategy.java1
-rw-r--r--services/core/java/com/android/server/display/brightness/strategy/OverrideBrightnessStrategy.java3
-rw-r--r--services/core/java/com/android/server/display/brightness/strategy/ScreenOffBrightnessStrategy.java1
-rw-r--r--services/core/java/com/android/server/display/brightness/strategy/TemporaryBrightnessStrategy.java1
-rw-r--r--services/core/java/com/android/server/display/config/DisplayDeviceConfigUtils.java63
-rw-r--r--services/core/java/com/android/server/display/config/HdrBrightnessData.java160
-rw-r--r--services/core/java/com/android/server/display/config/HighBrightnessModeData.java157
-rw-r--r--services/core/java/com/android/server/display/feature/DisplayManagerFlags.java13
-rw-r--r--services/core/java/com/android/server/display/feature/display_flags.aconfig8
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecNetwork.java6
-rw-r--r--services/core/java/com/android/server/inputmethod/AdditionalSubtypeMapRepository.java53
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java191
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodSettingsRepository.java40
-rw-r--r--services/core/java/com/android/server/inputmethod/SecureSettingsWrapper.java40
-rw-r--r--services/core/java/com/android/server/inputmethod/UserDataRepository.java72
-rw-r--r--services/core/java/com/android/server/location/contexthub/ContextHubTestModeManager.java25
-rw-r--r--services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java52
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java6
-rw-r--r--services/core/java/com/android/server/notification/ShortcutHelper.java162
-rw-r--r--services/core/java/com/android/server/notification/ZenModeEventLogger.java50
-rw-r--r--services/core/java/com/android/server/pm/InstallPackageHelper.java53
-rw-r--r--services/core/java/com/android/server/pm/PackageArchiver.java10
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerService.java15
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java20
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java15
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerServiceUtils.java19
-rw-r--r--services/core/java/com/android/server/pm/PackageSetting.java16
-rw-r--r--services/core/java/com/android/server/pm/ScanPackageUtils.java3
-rw-r--r--services/core/java/com/android/server/pm/Settings.java7
-rw-r--r--services/core/java/com/android/server/pm/ShortcutService.java13
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java33
-rw-r--r--services/core/java/com/android/server/pm/pkg/PackageState.java8
-rw-r--r--services/core/java/com/android/server/policy/ModifierShortcutManager.java149
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java24
-rw-r--r--services/core/java/com/android/server/policy/WindowManagerPolicy.java10
-rw-r--r--services/core/java/com/android/server/power/LowPowerStandbyController.java5
-rw-r--r--services/core/java/com/android/server/power/Notifier.java4
-rw-r--r--services/core/java/com/android/server/power/WakefulnessSessionObserver.java285
-rw-r--r--services/core/java/com/android/server/power/hint/HintManagerService.java335
-rw-r--r--services/core/java/com/android/server/power/stats/WifiPowerStatsCollector.java26
-rw-r--r--services/core/java/com/android/server/stats/pull/StatsPullAtomService.java13
-rw-r--r--services/core/java/com/android/server/trust/TrustManagerService.java23
-rw-r--r--services/core/java/com/android/server/updates/Android.bp11
-rw-r--r--services/core/java/com/android/server/updates/CertificateTransparencyLogInstallReceiver.java112
-rw-r--r--services/core/java/com/android/server/updates/flags.aconfig10
-rw-r--r--services/core/java/com/android/server/wm/AccessibilityController.java2
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java529
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java4
-rw-r--r--services/core/java/com/android/server/wm/AppCompatAspectRatioOverrides.java304
-rw-r--r--services/core/java/com/android/server/wm/AppCompatAspectRatioPolicy.java379
-rw-r--r--services/core/java/com/android/server/wm/AppCompatController.java21
-rw-r--r--services/core/java/com/android/server/wm/AppCompatOrientationOverrides.java4
-rw-r--r--services/core/java/com/android/server/wm/AppCompatOrientationPolicy.java30
-rw-r--r--services/core/java/com/android/server/wm/AppCompatOverrides.java79
-rw-r--r--services/core/java/com/android/server/wm/AppCompatUtils.java25
-rw-r--r--services/core/java/com/android/server/wm/AppTransitionController.java69
-rw-r--r--services/core/java/com/android/server/wm/BackgroundActivityStartController.java58
-rw-r--r--services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java10
-rw-r--r--services/core/java/com/android/server/wm/ConfigurationContainer.java117
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java104
-rw-r--r--services/core/java/com/android/server/wm/DisplayRotation.java1
-rw-r--r--services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java3
-rw-r--r--services/core/java/com/android/server/wm/LetterboxConfiguration.java31
-rw-r--r--services/core/java/com/android/server/wm/LetterboxUiController.java209
-rw-r--r--services/core/java/com/android/server/wm/RemoteAnimationController.java7
-rw-r--r--services/core/java/com/android/server/wm/Task.java37
-rw-r--r--services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java73
-rw-r--r--services/core/java/com/android/server/wm/Transition.java89
-rw-r--r--services/core/java/com/android/server/wm/WindowContainer.java12
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerFlags.java3
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java13
-rw-r--r--services/core/java/com/android/server/wm/WindowProcessController.java16
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java2
-rw-r--r--services/core/java/com/android/server/wm/WindowTracing.java299
-rw-r--r--services/core/java/com/android/server/wm/WindowTracingLegacy.java276
-rw-r--r--services/core/java/com/android/server/wm/utils/DimenPxIntSupplier.java54
-rw-r--r--services/core/jni/com_android_server_companion_virtual_InputController.cpp3
-rw-r--r--services/core/jni/com_android_server_input_InputManagerService.cpp11
-rw-r--r--services/core/xsd/display-device-config/display-device-config.xsd36
-rw-r--r--services/core/xsd/display-device-config/schema/current.txt8
-rw-r--r--services/java/com/android/server/SystemServer.java38
-rw-r--r--services/permission/java/com/android/server/permission/access/util/AtomicFileExtensions.kt3
-rw-r--r--services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java6
-rw-r--r--services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java59
-rw-r--r--services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceWindowGainedFocusTest.java4
-rw-r--r--services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/UserDataRepositoryTest.java83
-rw-r--r--services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/src/com/android/apps/inputmethod/simpleime/ims/InputMethodServiceWrapper.java15
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java19
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/DisplayBrightnessStateTest.java12
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java19
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java3
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/HighBrightnessModeControllerTest.java7
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/HighBrightnessModeMetadataMapperTest.java4
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java47
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/HdrClamperTest.java16
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutoBrightnessFallbackStrategyTest.java1
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java4
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/BoostBrightnessStrategyTest.java1
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/DozeBrightnessStrategyTest.java1
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/FallbackBrightnessStrategyTest.java1
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/FollowerBrightnessStrategyTest.java1
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/OffloadBrightnessStrategyTest.java1
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/OverrideBrightnessStrategyTest.java1
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/ScreenOffBrightnessStrategyTest.java1
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/TemporaryBrightnessStrategyTest.java1
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/config/DisplayDeviceConfigTestUtils.kt173
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/config/HdrBrightnessDataTest.kt158
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/mode/BrightnessObserverTest.kt1
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/mode/SettingsObserverTest.kt1
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/mode/TestUtils.kt15
-rw-r--r--services/tests/mockingservicestests/Android.bp1
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java5
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/ApplicationThreadDeferredTest.java99
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/AsyncProcessStartTest.java2
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java6
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/CacheOomRankerTest.java2
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java2
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/ProcessObserverTest.java2
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/ServiceBindingOomAdjPolicyTest.java2
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/ServiceTimeoutTest.java2
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/backup/utils/TarBackupReaderTest.java47
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/crashrecovery/Android.bp58
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/crashrecovery/AndroidManifest.xml32
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/crashrecovery/AndroidTest.xml34
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/crashrecovery/CrashRecoveryModuleTest.java103
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/crashrecovery/OWNERS1
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java42
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/WifiPowerStatsCollectorTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/AccessibilityUserStateTest.java14
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/MouseKeysInterceptorTest.kt45
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiCecNetworkTest.java9
-rw-r--r--services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java86
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java36
-rw-r--r--services/tests/servicestests/src/com/android/server/power/WakefulnessSessionObserverTest.java222
-rw-r--r--services/tests/servicestests/src/com/android/server/power/hint/HintManagerServiceTest.java7
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationAttentionHelperTest.java4
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java43
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/ShortcutHelperTest.java212
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/ZenModeEventLoggerFake.java5
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java117
-rw-r--r--services/tests/wmtests/AndroidManifest.xml1
-rw-r--r--services/tests/wmtests/res/xml/bookmarks.xml41
-rw-r--r--services/tests/wmtests/src/com/android/server/policy/ModifierShortcutManagerTests.java167
-rw-r--r--services/tests/wmtests/src/com/android/server/policy/ModifierShortcutTests.java3
-rw-r--r--services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java4
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java6
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/AppCompatActivityRobot.java17
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java371
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/BackgroundLaunchProcessControllerTests.java69
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java40
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java36
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java100
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java22
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java365
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java14
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java12
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskTests.java16
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java7
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java32
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java36
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTracingLegacyTest.java (renamed from services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java)4
-rw-r--r--telecomm/java/android/telecom/CallAudioState.java2
-rw-r--r--telephony/java/android/telephony/satellite/SatelliteManager.java11
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephony.aidl2
-rw-r--r--tests/FlickerTests/IME/Android.bp19
-rw-r--r--tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/DesktopModeAppHelper.kt33
-rw-r--r--tests/Input/AndroidTest.xml2
-rw-r--r--tests/Input/src/com/android/test/input/PointerIconLoadingTest.kt6
-rw-r--r--tests/Internal/src/com/android/internal/protolog/LegacyProtoLogViewerConfigReaderTest.java114
-rw-r--r--tests/Internal/src/com/android/internal/protolog/ProtoLogViewerConfigReaderTest.java137
-rw-r--r--tests/TrustTests/src/android/trust/test/UnlockAttemptTest.kt9
-rw-r--r--tests/inputmethod/ConcurrentMultiSessionImeTest/src/com/android/server/inputmethod/multisessiontest/ConcurrentMultiUserTest.java109
-rw-r--r--tests/inputmethod/ConcurrentMultiSessionImeTest/src/com/android/server/inputmethod/multisessiontest/MainActivity.java93
-rw-r--r--tests/inputmethod/ConcurrentMultiSessionImeTest/src/com/android/server/inputmethod/multisessiontest/TestRequestConstants.java10
-rw-r--r--tools/aapt2/cmd/Optimize.h4
-rw-r--r--tools/aapt2/link/ManifestFixer.cpp63
-rw-r--r--tools/aapt2/link/ManifestFixer.h2
-rw-r--r--tools/aapt2/link/ManifestFixer_test.cpp113
-rw-r--r--tools/aapt2/util/Files.cpp2
-rw-r--r--tools/aapt2/util/Files.h2
-rw-r--r--tools/app_metadata_bundles/src/lib/java/com/android/asllib/AslConverter.java14
-rw-r--r--tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AndroidSafetyLabel.java24
-rw-r--r--tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AndroidSafetyLabelFactory.java96
-rw-r--r--tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AppInfo.java168
-rw-r--r--tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AppInfoFactory.java227
-rw-r--r--tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AslMarshallable.java9
-rw-r--r--tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AslMarshallableFactory.java10
-rw-r--r--tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataCategory.java10
-rw-r--r--tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataCategoryFactory.java8
-rw-r--r--tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataLabels.java13
-rw-r--r--tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataLabelsFactory.java10
-rw-r--r--tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataType.java7
-rw-r--r--tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataTypeFactory.java3
-rw-r--r--tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DeveloperInfo.java167
-rw-r--r--tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DeveloperInfoFactory.java89
-rw-r--r--tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SafetyLabels.java42
-rw-r--r--tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SafetyLabelsFactory.java105
-rw-r--r--tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SecurityLabels.java12
-rw-r--r--tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SecurityLabelsFactory.java12
-rw-r--r--tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SystemAppSafetyLabel.java35
-rw-r--r--tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SystemAppSafetyLabelFactory.java63
-rw-r--r--tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/ThirdPartyVerification.java12
-rw-r--r--tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/ThirdPartyVerificationFactory.java12
-rw-r--r--tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/TransparencyInfo.java32
-rw-r--r--tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/TransparencyInfoFactory.java69
-rw-r--r--tools/app_metadata_bundles/src/lib/java/com/android/asllib/util/XmlUtils.java173
-rw-r--r--tools/app_metadata_bundles/src/test/java/com/android/asllib/AslgenTests.java12
-rw-r--r--tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/AndroidSafetyLabelTest.java72
-rw-r--r--tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/AppInfoTest.java153
-rw-r--r--tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/DataLabelsTest.java58
-rw-r--r--tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/SafetyLabelsTest.java66
-rw-r--r--tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/SystemAppSafetyLabelTest.java66
-rw-r--r--tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/TransparencyInfoTest.java37
-rw-r--r--tools/app_metadata_bundles/src/test/java/com/android/asllib/testutils/TestUtils.java114
-rw-r--r--tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/missing-version.xml16
-rw-r--r--tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/valid-empty.xml18
-rw-r--r--tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/with-safety-labels.xml17
-rw-r--r--tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/with-system-app-safety-label.xml4
-rw-r--r--tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/with-transparency-info.xml15
-rw-r--r--tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/missing-version.xml18
-rw-r--r--tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/valid-empty.xml20
-rw-r--r--tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/with-safety-labels.xml23
-rw-r--r--tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/with-system-app-safety-label.xml6
-rw-r--r--tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/with-transparency-info.xml16
-rw-r--r--tools/app_metadata_bundles/src/test/resources/com/android/asllib/appinfo/hr/all-fields-valid.xml2
-rw-r--r--tools/app_metadata_bundles/src/test/resources/com/android/asllib/appinfo/od/all-fields-valid-v1.xml24
-rw-r--r--tools/app_metadata_bundles/src/test/resources/com/android/asllib/appinfo/od/all-fields-valid.xml4
-rw-r--r--tools/app_metadata_bundles/src/test/resources/com/android/asllib/appinfo/od/unrecognized-v1.xml25
-rw-r--r--tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/hr/with-app-info.xml2
-rw-r--r--tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/hr/with-developer-info.xml11
-rw-r--r--tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/od/with-app-info.xml4
-rw-r--r--tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/od/with-developer-info.xml13
-rw-r--r--tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/general-v1/od.xml70
-rw-r--r--tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/general/hr.xml17
-rw-r--r--tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/general/od.xml6
1089 files changed, 23160 insertions, 14757 deletions
diff --git a/api/Android.bp b/api/Android.bp
index cd1997c8bf97..6a04f0d76bf9 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -368,8 +368,6 @@ stubs_defaults {
"--hide CallbackInterface",
// Disable HiddenSuperclass, as Metalava handles this fine (it should be hidden by default)
"--hide HiddenSuperclass",
- "--hide-package android.audio.policy.configuration.V7_0",
- "--hide-package com.android.server",
"--manifest $(location :frameworks-base-core-AndroidManifest.xml)",
],
filter_packages: packages_to_document,
diff --git a/core/api/current.txt b/core/api/current.txt
index 46f426b9f8e9..9ad8dd3ab9de 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -1058,7 +1058,7 @@ package android {
field public static final int label = 16842753; // 0x1010001
field public static final int labelFor = 16843718; // 0x10103c6
field @Deprecated public static final int labelTextSize = 16843317; // 0x1010235
- field @FlaggedApi("android.view.inputmethod.ime_switcher_revamp") public static final int languageSettingsActivity;
+ field @FlaggedApi("android.view.inputmethod.ime_switcher_revamp_api") public static final int languageSettingsActivity;
field public static final int languageTag = 16844040; // 0x1010508
field public static final int largeHeap = 16843610; // 0x101035a
field public static final int largeScreens = 16843398; // 0x1010286
@@ -6844,6 +6844,9 @@ package android.app {
method public android.app.Notification.MessagingStyle.Message setData(String, android.net.Uri);
}
+ @FlaggedApi("android.app.api_rich_ongoing") public abstract static class Notification.RichOngoingStyle extends android.app.Notification.Style {
+ }
+
public abstract static class Notification.Style {
ctor @Deprecated public Notification.Style();
method public android.app.Notification build();
@@ -11394,7 +11397,7 @@ package android.content {
field public static final String EXTRA_LOCALE_LIST = "android.intent.extra.LOCALE_LIST";
field public static final String EXTRA_LOCAL_ONLY = "android.intent.extra.LOCAL_ONLY";
field public static final String EXTRA_LOCUS_ID = "android.intent.extra.LOCUS_ID";
- field @FlaggedApi("android.service.chooser.enable_sharesheet_metadata_extra") public static final String EXTRA_METADATA_TEXT = "android.intent.extra.METADATA_TEXT";
+ field public static final String EXTRA_METADATA_TEXT = "android.intent.extra.METADATA_TEXT";
field public static final String EXTRA_MIME_TYPES = "android.intent.extra.MIME_TYPES";
field public static final String EXTRA_NOT_UNKNOWN_SOURCE = "android.intent.extra.NOT_UNKNOWN_SOURCE";
field public static final String EXTRA_ORIGINATING_URI = "android.intent.extra.ORIGINATING_URI";
@@ -11603,6 +11606,7 @@ package android.content {
method public static android.content.IntentSender readIntentSenderOrNullFromParcel(android.os.Parcel);
method public void sendIntent(android.content.Context, int, android.content.Intent, android.content.IntentSender.OnFinished, android.os.Handler) throws android.content.IntentSender.SendIntentException;
method public void sendIntent(android.content.Context, int, android.content.Intent, android.content.IntentSender.OnFinished, android.os.Handler, String) throws android.content.IntentSender.SendIntentException;
+ method @FlaggedApi("com.android.window.flags.bal_send_intent_with_options") public void sendIntent(@Nullable android.content.Context, int, @Nullable android.content.Intent, @Nullable String, @Nullable android.os.Bundle, @Nullable java.util.concurrent.Executor, @Nullable android.content.IntentSender.OnFinished) throws android.content.IntentSender.SendIntentException;
method public static void writeIntentSenderOrNullToParcel(android.content.IntentSender, android.os.Parcel);
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.content.IntentSender> CREATOR;
@@ -12043,6 +12047,7 @@ package android.content.pm {
field public static final int COLOR_MODE_DEFAULT = 0; // 0x0
field public static final int COLOR_MODE_HDR = 2; // 0x2
field public static final int COLOR_MODE_WIDE_COLOR_GAMUT = 1; // 0x1
+ field @FlaggedApi("android.content.res.handle_all_config_changes") public static final int CONFIG_ASSETS_PATHS = -2147483648; // 0x80000000
field public static final int CONFIG_COLOR_MODE = 16384; // 0x4000
field public static final int CONFIG_DENSITY = 4096; // 0x1000
field public static final int CONFIG_FONT_SCALE = 1073741824; // 0x40000000
@@ -12056,6 +12061,7 @@ package android.content.pm {
field public static final int CONFIG_MNC = 2; // 0x2
field public static final int CONFIG_NAVIGATION = 64; // 0x40
field public static final int CONFIG_ORIENTATION = 128; // 0x80
+ field @FlaggedApi("android.content.res.handle_all_config_changes") public static final int CONFIG_RESOURCES_UNUSED = 134217728; // 0x8000000
field public static final int CONFIG_SCREEN_LAYOUT = 256; // 0x100
field public static final int CONFIG_SCREEN_SIZE = 1024; // 0x400
field public static final int CONFIG_SMALLEST_SCREEN_SIZE = 2048; // 0x800
@@ -56332,7 +56338,7 @@ package android.view.inputmethod {
public final class InputMethodInfo implements android.os.Parcelable {
ctor public InputMethodInfo(android.content.Context, android.content.pm.ResolveInfo) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
ctor public InputMethodInfo(String, String, CharSequence, String);
- method @FlaggedApi("android.view.inputmethod.ime_switcher_revamp") @Nullable public android.content.Intent createImeLanguageSettingsActivityIntent();
+ method @FlaggedApi("android.view.inputmethod.ime_switcher_revamp_api") @Nullable public android.content.Intent createImeLanguageSettingsActivityIntent();
method @Nullable public android.content.Intent createStylusHandwritingSettingsActivityIntent();
method public int describeContents();
method public void dump(android.util.Printer, String);
@@ -56353,7 +56359,7 @@ package android.view.inputmethod {
method public boolean supportsStylusHandwriting();
method public boolean suppressesSpellChecker();
method public void writeToParcel(android.os.Parcel, int);
- field @FlaggedApi("android.view.inputmethod.ime_switcher_revamp") public static final String ACTION_IME_LANGUAGE_SETTINGS = "android.view.inputmethod.action.IME_LANGUAGE_SETTINGS";
+ field @FlaggedApi("android.view.inputmethod.ime_switcher_revamp_api") public static final String ACTION_IME_LANGUAGE_SETTINGS = "android.view.inputmethod.action.IME_LANGUAGE_SETTINGS";
field public static final String ACTION_STYLUS_HANDWRITING_SETTINGS = "android.view.inputmethod.action.STYLUS_HANDWRITING_SETTINGS";
field @NonNull public static final android.os.Parcelable.Creator<android.view.inputmethod.InputMethodInfo> CREATOR;
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index b384326201fc..36b1eaba89df 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -30,6 +30,7 @@ import static android.app.servertransaction.ActivityLifecycleItem.ON_STOP;
import static android.app.servertransaction.ActivityLifecycleItem.PRE_ON_CREATE;
import static android.content.ContentResolver.DEPRECATE_DATA_COLUMNS;
import static android.content.ContentResolver.DEPRECATE_DATA_PREFIX;
+import static android.content.pm.ActivityInfo.CONFIG_RESOURCES_UNUSED;
import static android.content.res.Configuration.UI_MODE_TYPE_DESK;
import static android.content.res.Configuration.UI_MODE_TYPE_MASK;
import static android.view.Display.DEFAULT_DISPLAY;
@@ -41,7 +42,6 @@ import static android.window.ConfigurationHelper.shouldUpdateResources;
import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
import static com.android.internal.os.SafeZipPathValidatorCallback.VALIDATE_ZIP_PATH_FOR_PATH_TRAVERSAL;
import static com.android.sdksandbox.flags.Flags.sandboxActivitySdkBasedContext;
-import static com.android.window.flags.Flags.activityWindowInfoFlag;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -6520,6 +6520,13 @@ public final class ActivityThread extends ClientTransactionHandler
return true;
}
+ if (android.content.res.Flags.handleAllConfigChanges()) {
+ if ((handledConfigChanges & CONFIG_RESOURCES_UNUSED) != 0) {
+ // Report the change if activities claim they do not use resources at all.
+ return true;
+ }
+ }
+
final int diffWithBucket = SizeConfigurationBuckets.filterDiff(publicDiff, currentConfig,
newConfig, sizeBuckets);
// Compare to the diff which filter the change without crossing size buckets with
@@ -6846,9 +6853,6 @@ public final class ActivityThread extends ClientTransactionHandler
}
private void handleActivityWindowInfoChanged(@NonNull ActivityClientRecord r) {
- if (!activityWindowInfoFlag()) {
- return;
- }
if (r.mActivityWindowInfo.equals(r.mLastReportedActivityWindowInfo)) {
return;
}
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index db979a5dd30b..ef09dc45d423 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -10979,6 +10979,18 @@ public class Notification implements Parcelable
}
/**
+ * An object that can apply a rich ongoing notification style to a {@link Notification.Builder}
+ * object.
+ */
+ @FlaggedApi(Flags.FLAG_API_RICH_ONGOING)
+ public abstract static class RichOngoingStyle extends Notification.Style {
+ /**
+ * @hide
+ */
+ public RichOngoingStyle() {}
+ }
+
+ /**
* Notification style for custom views that are decorated by the system
*
* <p>Instead of providing a notification that is completely custom, a developer can set this
diff --git a/core/java/android/app/servertransaction/ClientTransactionListenerController.java b/core/java/android/app/servertransaction/ClientTransactionListenerController.java
index 0c1e7a32ae5e..c281533ee299 100644
--- a/core/java/android/app/servertransaction/ClientTransactionListenerController.java
+++ b/core/java/android/app/servertransaction/ClientTransactionListenerController.java
@@ -19,8 +19,6 @@ package android.app.servertransaction;
import static android.app.WindowConfiguration.areConfigurationsEqualForDisplay;
import static android.view.Display.INVALID_DISPLAY;
-import static com.android.window.flags.Flags.activityWindowInfoFlag;
-
import static java.util.Objects.requireNonNull;
import android.annotation.NonNull;
@@ -102,9 +100,6 @@ public class ClientTransactionListenerController {
*/
public void registerActivityWindowInfoChangedListener(
@NonNull BiConsumer<IBinder, ActivityWindowInfo> listener) {
- if (!activityWindowInfoFlag()) {
- return;
- }
synchronized (mLock) {
mActivityWindowInfoChangedListeners.add(listener);
}
@@ -116,9 +111,6 @@ public class ClientTransactionListenerController {
*/
public void unregisterActivityWindowInfoChangedListener(
@NonNull BiConsumer<IBinder, ActivityWindowInfo> listener) {
- if (!activityWindowInfoFlag()) {
- return;
- }
synchronized (mLock) {
mActivityWindowInfoChangedListeners.remove(listener);
}
@@ -130,9 +122,6 @@ public class ClientTransactionListenerController {
*/
public void onActivityWindowInfoChanged(@NonNull IBinder activityToken,
@NonNull ActivityWindowInfo activityWindowInfo) {
- if (!activityWindowInfoFlag()) {
- return;
- }
final Object[] activityWindowInfoChangedListeners;
synchronized (mLock) {
if (mActivityWindowInfoChangedListeners.isEmpty()) {
diff --git a/core/java/android/audio/policy/configuration/V7_0/package-info.java b/core/java/android/audio/policy/configuration/V7_0/package-info.java
new file mode 100644
index 000000000000..8f7425fc2b5b
--- /dev/null
+++ b/core/java/android/audio/policy/configuration/V7_0/package-info.java
@@ -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.
+ */
+
+/**
+ * Hide the android.audio.policy.configuration.V7_0 API as that is managed
+ * separately.
+ *
+ * @hide
+ */
+package android.audio.policy.configuration.V7_0;
diff --git a/core/java/android/companion/virtual/flags/flags.aconfig b/core/java/android/companion/virtual/flags/flags.aconfig
index d05d23c336c2..55278f617ba9 100644
--- a/core/java/android/companion/virtual/flags/flags.aconfig
+++ b/core/java/android/companion/virtual/flags/flags.aconfig
@@ -32,6 +32,13 @@ flag {
}
flag {
+ namespace: "virtual_devices"
+ name: "media_projection_keyguard_restrictions"
+ description: "Auto-stop MP when the device locks"
+ bug: "348335290"
+}
+
+flag {
namespace: "virtual_devices"
name: "virtual_display_insets"
description: "APIs for specifying virtual display insets (via cutout)"
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 87fb84331af3..385d6cfd14a0 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -61,6 +61,7 @@ import android.os.storage.StorageManager;
import android.permission.PermissionCheckerManager;
import android.provider.MediaStore;
import android.text.TextUtils;
+import android.util.ArraySet;
import android.util.Log;
import android.util.SparseBooleanArray;
@@ -486,6 +487,8 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
validateIncomingAuthority(authority);
int numOperations = operations.size();
final int[] userIds = new int[numOperations];
+ final ArraySet<String> readPermissions = new ArraySet<String>();
+ final ArraySet<String> writePermissions = new ArraySet<String>();
for (int i = 0; i < numOperations; i++) {
ContentProviderOperation operation = operations.get(i);
Uri uri = operation.getUri();
@@ -499,17 +502,19 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
}
final AttributionSource accessAttributionSource =
attributionSource;
- if (operation.isReadOperation()) {
+ if (operation.isReadOperation() && !readPermissions.contains(uri.toString())) {
if (enforceReadPermission(accessAttributionSource, uri)
!= PermissionChecker.PERMISSION_GRANTED) {
throw new OperationApplicationException("App op not allowed", 0);
}
+ readPermissions.add(uri.toString());
}
- if (operation.isWriteOperation()) {
+ if (operation.isWriteOperation() && !writePermissions.contains(uri.toString())) {
if (enforceWritePermission(accessAttributionSource, uri)
!= PermissionChecker.PERMISSION_GRANTED) {
throw new OperationApplicationException("App op not allowed", 0);
}
+ writePermissions.add(uri.toString());
}
}
traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "applyBatch: ", authority);
@@ -2774,6 +2779,10 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
+ " provider from user:" + mContext.getUserId());
}
if (userId != UserHandle.USER_CURRENT
+ // getUserIdFromAuthority can return USER_NULL when can't cast the userId to
+ // an int, which can cause high volume of binder calls.
+ && (!android.multiuser.Flags.fixGetUserPropertyCache()
+ || userId != UserHandle.USER_NULL)
&& userId != mContext.getUserId()
// Since userId specified in content uri, the provider userId would be
// determined from it.
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 112507e00e85..97404dcdea0c 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -20,7 +20,6 @@ import static android.app.sdksandbox.SdkSandboxManager.ACTION_START_SANDBOXED_AC
import static android.content.ContentProvider.maybeAddUserId;
import static android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE;
import static android.security.Flags.FLAG_FRP_ENFORCEMENT;
-import static android.service.chooser.Flags.FLAG_ENABLE_SHARESHEET_METADATA_EXTRA;
import android.Manifest;
import android.accessibilityservice.AccessibilityService;
@@ -6252,7 +6251,6 @@ public class Intent implements Parcelable, Cloneable {
* <p>e.g. When sharing a photo, metadata could inform the user that location data is included
* in the photo they are sharing.</p>
*/
- @FlaggedApi(FLAG_ENABLE_SHARESHEET_METADATA_EXTRA)
public static final String EXTRA_METADATA_TEXT = "android.intent.extra.METADATA_TEXT";
/**
diff --git a/core/java/android/content/IntentSender.java b/core/java/android/content/IntentSender.java
index 2e252c12c51d..32d1964dd4f0 100644
--- a/core/java/android/content/IntentSender.java
+++ b/core/java/android/content/IntentSender.java
@@ -16,6 +16,7 @@
package android.content;
+import android.annotation.FlaggedApi;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityManager.PendingIntentInfo;
@@ -32,6 +33,10 @@ import android.os.RemoteException;
import android.os.UserHandle;
import android.util.AndroidException;
+import com.android.window.flags.Flags;
+
+import java.util.concurrent.Executor;
+
/**
* A description of an Intent and target action to perform with it.
* The returned object can be
@@ -114,15 +119,15 @@ public class IntentSender implements Parcelable {
implements Runnable {
private final IntentSender mIntentSender;
private final OnFinished mWho;
- private final Handler mHandler;
+ private final Executor mExecutor;
private Intent mIntent;
private int mResultCode;
private String mResultData;
private Bundle mResultExtras;
- FinishedDispatcher(IntentSender pi, OnFinished who, Handler handler) {
+ FinishedDispatcher(IntentSender pi, OnFinished who, Executor executor) {
mIntentSender = pi;
mWho = who;
- mHandler = handler;
+ mExecutor = executor;
}
public void performReceive(Intent intent, int resultCode, String data,
Bundle extras, boolean serialized, boolean sticky, int sendingUser) {
@@ -130,10 +135,10 @@ public class IntentSender implements Parcelable {
mResultCode = resultCode;
mResultData = data;
mResultExtras = extras;
- if (mHandler == null) {
+ if (mExecutor == null) {
run();
} else {
- mHandler.post(this);
+ mExecutor.execute(this);
}
}
public void run() {
@@ -147,16 +152,16 @@ public class IntentSender implements Parcelable {
* caller to specify information about the Intent to use and be notified
* when the send has completed.
*
- * @param context The Context of the caller. This may be null if
- * <var>intent</var> is also null.
+ * @param context The Context of the caller. This may be {@code null} if
+ * <var>intent</var> is also {@code null}.
* @param code Result code to supply back to the IntentSender's target.
* @param intent Additional Intent data. See {@link Intent#fillIn
* Intent.fillIn()} for information on how this is applied to the
- * original Intent. Use null to not modify the original Intent.
+ * original Intent. Use {@code null} to not modify the original Intent.
* @param onFinished The object to call back on when the send has
- * completed, or null for no callback.
+ * completed, or {@code null} for no callback.
* @param handler Handler identifying the thread on which the callback
- * should happen. If null, the callback will happen from the thread
+ * should happen. If {@code null}, the callback will happen from the thread
* pool of the process.
*
*
@@ -165,8 +170,8 @@ public class IntentSender implements Parcelable {
*/
public void sendIntent(Context context, int code, Intent intent,
OnFinished onFinished, Handler handler) throws SendIntentException {
- sendIntent(context, code, intent, onFinished, handler, null,
- SEND_INTENT_DEFAULT_OPTIONS);
+ sendIntent(context, code, intent, null, SEND_INTENT_DEFAULT_OPTIONS,
+ handler == null ? null : handler::post, onFinished);
}
/**
@@ -174,22 +179,22 @@ public class IntentSender implements Parcelable {
* caller to specify information about the Intent to use and be notified
* when the send has completed.
*
- * @param context The Context of the caller. This may be null if
- * <var>intent</var> is also null.
+ * @param context The Context of the caller. This may be {@code null} if
+ * <var>intent</var> is also {@code null}.
* @param code Result code to supply back to the IntentSender's target.
* @param intent Additional Intent data. See {@link Intent#fillIn
* Intent.fillIn()} for information on how this is applied to the
- * original Intent. Use null to not modify the original Intent.
+ * original Intent. Use {@code null} to not modify the original Intent.
* @param onFinished The object to call back on when the send has
- * completed, or null for no callback.
+ * completed, or {@code null} for no callback.
* @param handler Handler identifying the thread on which the callback
- * should happen. If null, the callback will happen from the thread
+ * should happen. If {@code null}, the callback will happen from the thread
* pool of the process.
* @param requiredPermission Name of permission that a recipient of the PendingIntent
* is required to hold. This is only valid for broadcast intents, and
* corresponds to the permission argument in
* {@link Context#sendBroadcast(Intent, String) Context.sendOrderedBroadcast(Intent, String)}.
- * If null, no permission is required.
+ * If {@code null}, no permission is required.
*
*
* @throws SendIntentException Throws CanceledIntentException if the IntentSender
@@ -198,8 +203,8 @@ public class IntentSender implements Parcelable {
public void sendIntent(Context context, int code, Intent intent,
OnFinished onFinished, Handler handler, String requiredPermission)
throws SendIntentException {
- sendIntent(context, code, intent, onFinished, handler, requiredPermission,
- SEND_INTENT_DEFAULT_OPTIONS);
+ sendIntent(context, code, intent, requiredPermission, SEND_INTENT_DEFAULT_OPTIONS,
+ handler == null ? null : handler::post, onFinished);
}
/**
@@ -207,32 +212,32 @@ public class IntentSender implements Parcelable {
* caller to specify information about the Intent to use and be notified
* when the send has completed.
*
- * @param context The Context of the caller. This may be null if
- * <var>intent</var> is also null.
+ * @param context The Context of the caller. This may be {@code null} if
+ * <var>intent</var> is also {@code null}.
* @param code Result code to supply back to the IntentSender's target.
* @param intent Additional Intent data. See {@link Intent#fillIn
* Intent.fillIn()} for information on how this is applied to the
- * original Intent. Use null to not modify the original Intent.
+ * original Intent. Use {@code null} to not modify the original Intent.
* @param onFinished The object to call back on when the send has
- * completed, or null for no callback.
- * @param handler Handler identifying the thread on which the callback
- * should happen. If null, the callback will happen from the thread
+ * completed, or {@code null} for no callback.
+ * @param executor Executor identifying the thread on which the callback
+ * should happen. If {@code null}, the callback will happen from the thread
* pool of the process.
* @param requiredPermission Name of permission that a recipient of the PendingIntent
* is required to hold. This is only valid for broadcast intents, and
* corresponds to the permission argument in
* {@link Context#sendBroadcast(Intent, String) Context.sendOrderedBroadcast(Intent, String)}.
- * If null, no permission is required.
+ * If {@code null}, no permission is required.
* @param options Additional options the caller would like to provide to modify the sending
- * behavior. May be built from an {@link ActivityOptions} to apply to an activity start.
+ * behavior. Typically built from using {@link ActivityOptions} to apply to an activity start.
*
* @throws SendIntentException Throws CanceledIntentException if the IntentSender
* is no longer allowing more intents to be sent through it.
- * @hide
*/
- public void sendIntent(Context context, int code, Intent intent,
- OnFinished onFinished, Handler handler, String requiredPermission,
- @Nullable Bundle options)
+ @FlaggedApi(Flags.FLAG_BAL_SEND_INTENT_WITH_OPTIONS)
+ public void sendIntent(@Nullable Context context, int code, @Nullable Intent intent,
+ @Nullable String requiredPermission, @Nullable Bundle options,
+ @Nullable Executor executor, @Nullable OnFinished onFinished)
throws SendIntentException {
try {
String resolvedType = intent != null ?
@@ -243,7 +248,7 @@ public class IntentSender implements Parcelable {
int res = ActivityManager.getService().sendIntentSender(app, mTarget, mWhitelistToken,
code, intent, resolvedType,
onFinished != null
- ? new FinishedDispatcher(this, onFinished, handler)
+ ? new FinishedDispatcher(this, onFinished, executor)
: null,
requiredPermission, options);
if (res < 0) {
@@ -268,7 +273,7 @@ public class IntentSender implements Parcelable {
* sending the Intent. The returned string is supplied by the system, so
* that an application can not spoof its package.
*
- * @return The package name of the PendingIntent, or null if there is
+ * @return The package name of the PendingIntent, or {@code null} if there is
* none associated with it.
*/
public String getCreatorPackage() {
@@ -296,7 +301,7 @@ public class IntentSender implements Parcelable {
* {@link android.os.Process#myUserHandle() Process.myUserHandle()} for
* more explanation of user handles.
*
- * @return The user handle of the PendingIntent, or null if there is
+ * @return The user handle of the PendingIntent, {@code null} if there is
* none associated with it.
*/
public UserHandle getCreatorUserHandle() {
@@ -355,11 +360,11 @@ public class IntentSender implements Parcelable {
};
/**
- * Convenience function for writing either a IntentSender or null pointer to
+ * Convenience function for writing either a IntentSender or {@code null} pointer to
* a Parcel. You must use this with {@link #readIntentSenderOrNullFromParcel}
* for later reading it.
*
- * @param sender The IntentSender to write, or null.
+ * @param sender The IntentSender to write, or {@code null}.
* @param out Where to write the IntentSender.
*/
public static void writeIntentSenderOrNullToParcel(IntentSender sender,
@@ -369,13 +374,13 @@ public class IntentSender implements Parcelable {
}
/**
- * Convenience function for reading either a Messenger or null pointer from
+ * Convenience function for reading either a Messenger or {@code null} pointer from
* a Parcel. You must have previously written the Messenger with
* {@link #writeIntentSenderOrNullToParcel}.
*
* @param in The Parcel containing the written Messenger.
*
- * @return Returns the Messenger read from the Parcel, or null if null had
+ * @return Returns the Messenger read from the Parcel, or @code null} if @code null} had
* been written.
*/
public static IntentSender readIntentSenderOrNullFromParcel(Parcel in) {
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 57ffed47bbe3..6952a09f2d90 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -941,6 +941,8 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
CONFIG_COLOR_MODE,
CONFIG_FONT_SCALE,
CONFIG_GRAMMATICAL_GENDER,
+ CONFIG_ASSETS_PATHS,
+ CONFIG_RESOURCES_UNUSED,
})
@Retention(RetentionPolicy.SOURCE)
public @interface Config {}
@@ -1060,8 +1062,8 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
* can itself handle asset path changes. Set from the {@link android.R.attr#configChanges}
* attribute. This is not a core resource configuration, but a higher-level value, so its
* constant starts at the high bits.
- * @hide We do not want apps handling this yet, but we do need some kind of bit for diffs.
*/
+ @FlaggedApi(android.content.res.Flags.FLAG_HANDLE_ALL_CONFIG_CHANGES)
public static final int CONFIG_ASSETS_PATHS = 0x80000000;
/**
* Bit in {@link #configChanges} that indicates that the activity
@@ -1088,6 +1090,30 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
*/
public static final int CONFIG_FONT_WEIGHT_ADJUSTMENT = 0x10000000;
+ /**
+ * <p>This is probably not the constant you want, the resources compiler supports a less
+ * dangerous version of it, 'allKnown', that only suppresses all currently existing
+ * configuration change restarts depending on your target SDK rather than whatever the latest
+ * SDK supports, allowing the application to work with resources on future Platform versions.
+ *
+ * <p>Bit in {@link #configChanges} that indicates that the activity doesn't use Android
+ * Resources at all and doesn't need to be restarted on any configuration changes. This bit
+ * disables all restarts for configuration dimensions available in the current target SDK as
+ * well as dimensions introduced in future SDKs. Use it only if the activity doesn't need
+ * anything from its resources, and doesn't depend on any libraries that may provide resources
+ * and need to respond to configuration changes. When set,
+ * {@link Activity#onConfigurationChanged(Configuration)} will be called instead of a restart,
+ * and it’s up to the implementation to ensure that no stale resource values remain loaded
+ * anywhere in the code.
+ *
+ * <p>This overrides all other bits, and this is recommended to be used individually.
+ *
+ * <p>This is not a core resource configuration, but a higher-level value, so its constant
+ * starts at the high bits.
+ */
+ @FlaggedApi(android.content.res.Flags.FLAG_HANDLE_ALL_CONFIG_CHANGES)
+ public static final int CONFIG_RESOURCES_UNUSED = 0x8000000;
+
/** @hide
* Unfortunately the constants for config changes in native code are
* different from ActivityInfo. :( Here are the values we should use for the
@@ -1657,7 +1683,8 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
* {@link #CONFIG_KEYBOARD}, {@link #CONFIG_NAVIGATION},
* {@link #CONFIG_ORIENTATION}, {@link #CONFIG_SCREEN_LAYOUT},
* {@link #CONFIG_DENSITY}, {@link #CONFIG_LAYOUT_DIRECTION},
- * {@link #CONFIG_COLOR_MODE}, and {link #CONFIG_GRAMMATICAL_GENDER}.
+ * {@link #CONFIG_COLOR_MODE}, {@link #CONFIG_GRAMMATICAL_GENDER},
+ * {@link #CONFIG_ASSETS_PATHS}, and {@link #CONFIG_RESOURCES_UNUSED}.
* Set from the {@link android.R.attr#configChanges} attribute.
*/
public int configChanges;
diff --git a/core/java/android/content/pm/ShortcutServiceInternal.java b/core/java/android/content/pm/ShortcutServiceInternal.java
index 55d0bc1deedc..c811a47e5b05 100644
--- a/core/java/android/content/pm/ShortcutServiceInternal.java
+++ b/core/java/android/content/pm/ShortcutServiceInternal.java
@@ -91,6 +91,9 @@ public abstract class ShortcutServiceInternal {
public abstract void addShortcutChangeCallback(
@NonNull LauncherApps.ShortcutChangeCallback callback);
+ public abstract void removeShortcutChangeCallback(
+ @NonNull LauncherApps.ShortcutChangeCallback callback);
+
public abstract int getShortcutIconResId(int launcherUserId, @NonNull String callingPackage,
@NonNull String packageName, @NonNull String shortcutId, int userId);
diff --git a/core/java/android/content/pm/multiuser.aconfig b/core/java/android/content/pm/multiuser.aconfig
index c7d94c66c81e..26ee4e821ede 100644
--- a/core/java/android/content/pm/multiuser.aconfig
+++ b/core/java/android/content/pm/multiuser.aconfig
@@ -161,6 +161,16 @@ flag {
}
flag {
+ name: "cache_profile_parent"
+ namespace: "multiuser"
+ description: "Cache getProfileParent to avoid unnecessary binder calls"
+ bug: "350417399"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "cache_quiet_mode_state"
namespace: "multiuser"
description: "Optimise quiet mode state retrieval"
diff --git a/core/java/android/content/res/flags.aconfig b/core/java/android/content/res/flags.aconfig
index a475cc85e921..a5f8199c9a07 100644
--- a/core/java/android/content/res/flags.aconfig
+++ b/core/java/android/content/res/flags.aconfig
@@ -56,3 +56,13 @@ flag {
# This flag is read in ResourcesImpl at boot time.
is_fixed_read_only: true
}
+
+flag {
+ name: "handle_all_config_changes"
+ is_exported: true
+ namespace: "resource_manager"
+ description: "Feature flag for allowing activities to handle all kinds of configuration changes"
+ bug: "180625460"
+ # This flag is read at boot time.
+ is_fixed_read_only: true
+}
diff --git a/core/java/android/hardware/OWNERS b/core/java/android/hardware/OWNERS
index 51ad1519941b..43d3f5466ccf 100644
--- a/core/java/android/hardware/OWNERS
+++ b/core/java/android/hardware/OWNERS
@@ -5,7 +5,7 @@ michaelwr@google.com
sumir@google.com
# Camera
-per-file *Camera*=cychen@google.com,epeev@google.com,etalvala@google.com,shuzhenwang@google.com,zhijunhe@google.com,jchowdhary@google.com
+per-file *Camera*=file:platform/frameworks/av:/camera/OWNERS
# Sensor Privacy
per-file *SensorPrivacy* = file:platform/frameworks/native:/libs/sensorprivacy/OWNERS
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 6201359ca53e..6a7ee7fcb26a 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -56,6 +56,8 @@ import android.hardware.camera2.utils.ConcurrentCameraIdCombination;
import android.hardware.camera2.utils.ExceptionUtils;
import android.hardware.devicestate.DeviceState;
import android.hardware.devicestate.DeviceStateManager;
+import android.hardware.devicestate.feature.flags.FeatureFlags;
+import android.hardware.devicestate.feature.flags.FeatureFlagsImpl;
import android.hardware.display.DisplayManager;
import android.os.Binder;
import android.os.Handler;
@@ -247,14 +249,22 @@ public final class CameraManager {
private ArrayList<WeakReference<DeviceStateListener>> mDeviceStateListeners =
new ArrayList<>();
private boolean mFoldedDeviceState;
+ private final FeatureFlags mDeviceStateManagerFlags;
public FoldStateListener(Context context) {
mFoldedDeviceStates = context.getResources().getIntArray(
com.android.internal.R.array.config_foldedDeviceStates);
+ mDeviceStateManagerFlags = new FeatureFlagsImpl();
}
- private synchronized void handleStateChange(int state) {
- boolean folded = ArrayUtils.contains(mFoldedDeviceStates, state);
+ private synchronized void handleStateChange(DeviceState state) {
+ final boolean folded;
+ if (mDeviceStateManagerFlags.deviceStatePropertyMigration()) {
+ folded = state.hasProperty(
+ DeviceState.PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY);
+ } else {
+ folded = ArrayUtils.contains(mFoldedDeviceStates, state.getIdentifier());
+ }
mFoldedDeviceState = folded;
Iterator<WeakReference<DeviceStateListener>> it = mDeviceStateListeners.iterator();
@@ -276,10 +286,8 @@ public final class CameraManager {
@SuppressWarnings("FlaggedApi")
@Override
- public void onDeviceStateChanged(DeviceState state) {
- // Suppressing the FlaggedAPI warning as this specific API isn't new, just moved to
- // system API which requires it to be flagged.
- handleStateChange(state.getIdentifier());
+ public void onDeviceStateChanged(@NonNull DeviceState state) {
+ handleStateChange(state);
}
}
diff --git a/core/java/android/hardware/devicestate/DeviceStateManager.java b/core/java/android/hardware/devicestate/DeviceStateManager.java
index febc24c1465a..5b511cc94ac0 100644
--- a/core/java/android/hardware/devicestate/DeviceStateManager.java
+++ b/core/java/android/hardware/devicestate/DeviceStateManager.java
@@ -67,6 +67,14 @@ public final class DeviceStateManager {
public static final int MAXIMUM_DEVICE_STATE_IDENTIFIER = 10000;
/**
+ * {@link DeviceState} to represent an invalid device state.
+ * @hide
+ */
+ public static final DeviceState INVALID_DEVICE_STATE = new DeviceState(
+ new DeviceState.Configuration.Builder(INVALID_DEVICE_STATE_IDENTIFIER,
+ "INVALID").build());
+
+ /**
* Intent needed to launch the rear display overlay activity from SysUI
*
* @hide
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 4894fb1ec452..0321e1dfee78 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -395,7 +395,7 @@ public final class DisplayManager {
* the display is removed.
*
* Public virtual displays without this flag will move their content to main display
- * stack once they're removed. Private vistual displays will always destroy their
+ * stack once they're removed. Private virtual displays will always destroy their
* content on removal even without this flag.
*
* @see #createVirtualDisplay
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index 91caedc0b9a9..811a834dff47 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -686,8 +686,12 @@ public abstract class DisplayManagerInternal {
public RefreshRateRange range;
public RefreshRateLimitation(@RefreshRateLimitType int type, float min, float max) {
+ this(type, new RefreshRateRange(min, max));
+ }
+
+ public RefreshRateLimitation(@RefreshRateLimitType int type, RefreshRateRange range) {
this.type = type;
- range = new RefreshRateRange(min, max);
+ this.range = range;
}
@Override
diff --git a/core/java/android/hardware/input/VirtualRotaryEncoderScrollEvent.java b/core/java/android/hardware/input/VirtualRotaryEncoderScrollEvent.java
index 3be911abe732..8c98abd6dbfe 100644
--- a/core/java/android/hardware/input/VirtualRotaryEncoderScrollEvent.java
+++ b/core/java/android/hardware/input/VirtualRotaryEncoderScrollEvent.java
@@ -107,7 +107,8 @@ public final class VirtualRotaryEncoderScrollEvent implements Parcelable {
}
/**
- * Sets the scroll amount, normalized from -1.0 to 1.0, inclusive.
+ * Sets the scroll amount, normalized from -1.0 to 1.0, inclusive. By default, the scroll
+ * amount is 0, which results in no scroll.
* <p>
* Positive values indicate scrolling forward (e.g. down in a vertical list); negative
* values, backward.
diff --git a/core/java/android/hardware/input/input_framework.aconfig b/core/java/android/hardware/input/input_framework.aconfig
index 16d9ef270f75..0cd280002dbf 100644
--- a/core/java/android/hardware/input/input_framework.aconfig
+++ b/core/java/android/hardware/input/input_framework.aconfig
@@ -68,3 +68,10 @@ flag {
description: "Controls if the mouse keys accessibility feature for physical keyboard is available to the user"
bug: "341799888"
}
+
+flag {
+ namespace: "input_native"
+ name: "touchpad_visualizer"
+ description: "Enables a developer overlay that displays raw touchpad input data and gesture recognition status in real-time."
+ bug: "286551975"
+}
diff --git a/core/java/android/inputmethodservice/ImsConfigurationTracker.java b/core/java/android/inputmethodservice/ImsConfigurationTracker.java
index 30ef0a2a6f7f..17a5ffcb1081 100644
--- a/core/java/android/inputmethodservice/ImsConfigurationTracker.java
+++ b/core/java/android/inputmethodservice/ImsConfigurationTracker.java
@@ -16,6 +16,8 @@
package android.inputmethodservice;
+import static android.content.pm.ActivityInfo.CONFIG_RESOURCES_UNUSED;
+
import android.annotation.MainThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -88,12 +90,16 @@ public final class ImsConfigurationTracker {
if (!mInitialized) {
return;
}
+ // Don't restart InputMethodService that claims it does not use resources at all.
+ boolean neverReset = android.content.res.Flags.handleAllConfigChanges()
+ && (mHandledConfigChanges & CONFIG_RESOURCES_UNUSED) != 0;
+
final int diff = mLastKnownConfig != null
? mLastKnownConfig.diffPublicOnly(newConfig) : CONFIG_CHANGED;
// If the new config is the same as the config this Service is already running with,
// then don't bother calling resetStateForNewConfiguration.
final int unhandledDiff = (diff & ~mHandledConfigChanges);
- if (unhandledDiff != 0) {
+ if (unhandledDiff != 0 && !neverReset) {
resetStateForNewConfigurationRunner.run();
}
if (diff != 0) {
diff --git a/core/java/android/inputmethodservice/navigationbar/NavigationBarConstants.java b/core/java/android/inputmethodservice/navigationbar/NavigationBarConstants.java
index 4bb66ed26cbc..93c54395f972 100644
--- a/core/java/android/inputmethodservice/navigationbar/NavigationBarConstants.java
+++ b/core/java/android/inputmethodservice/navigationbar/NavigationBarConstants.java
@@ -17,7 +17,6 @@
package android.inputmethodservice.navigationbar;
import android.annotation.ColorInt;
-import android.graphics.Color;
final class NavigationBarConstants {
private NavigationBarConstants() {
@@ -28,13 +27,13 @@ final class NavigationBarConstants {
// TODO(b/215443343): Handle this in the drawable then remove this constant.
static final float NAVBAR_BACK_BUTTON_IME_OFFSET = 2.0f;
- // Copied from "white" at packages/SettingsLib/res/values/colors.xml
+ // Copied from "light_mode_icon_color_single_tone" at packages/SettingsLib/res/values/colors.xml
@ColorInt
- static final int WHITE = Color.WHITE;
+ static final int LIGHT_MODE_ICON_COLOR_SINGLE_TONE = 0xffffffff;
- // Copied from "black" at packages/SettingsLib/res/values/colors.xml
+ // Copied from "dark_mode_icon_color_single_tone" at packages/SettingsLib/res/values/colors.xml
@ColorInt
- static final int BLACK = Color.BLACK;
+ static final int DARK_MODE_ICON_COLOR_SINGLE_TONE = 0x99000000;
// Copied from "navigation_bar_deadzone_hold"
static final int NAVIGATION_BAR_DEADZONE_HOLD = 333;
diff --git a/core/java/android/inputmethodservice/navigationbar/NavigationBarView.java b/core/java/android/inputmethodservice/navigationbar/NavigationBarView.java
index b522e9bdca45..e28f34528f42 100644
--- a/core/java/android/inputmethodservice/navigationbar/NavigationBarView.java
+++ b/core/java/android/inputmethodservice/navigationbar/NavigationBarView.java
@@ -16,8 +16,8 @@
package android.inputmethodservice.navigationbar;
-import static android.inputmethodservice.navigationbar.NavigationBarConstants.BLACK;
-import static android.inputmethodservice.navigationbar.NavigationBarConstants.WHITE;
+import static android.inputmethodservice.navigationbar.NavigationBarConstants.DARK_MODE_ICON_COLOR_SINGLE_TONE;
+import static android.inputmethodservice.navigationbar.NavigationBarConstants.LIGHT_MODE_ICON_COLOR_SINGLE_TONE;
import static android.inputmethodservice.navigationbar.NavigationBarConstants.NAVBAR_BACK_BUTTON_IME_OFFSET;
import static android.inputmethodservice.navigationbar.NavigationBarUtils.dpToPx;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
@@ -83,8 +83,8 @@ public final class NavigationBarView extends FrameLayout {
super(context, attrs);
mLightContext = context;
- mLightIconColor = WHITE;
- mDarkIconColor = BLACK;
+ mLightIconColor = LIGHT_MODE_ICON_COLOR_SINGLE_TONE;
+ mDarkIconColor = DARK_MODE_ICON_COLOR_SINGLE_TONE;
mConfiguration = new Configuration();
mTmpLastConfiguration = new Configuration();
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index f30a9f5411ee..3aa42c6bb594 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -3927,7 +3927,12 @@ public class UserManager {
android.Manifest.permission.QUERY_USERS,
android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional = true)
public @NonNull UserProperties getUserProperties(@NonNull UserHandle userHandle) {
- return mUserPropertiesCache.query(userHandle.getIdentifier());
+ final int userId = userHandle.getIdentifier();
+ // Avoid calling into system server for invalid user ids.
+ if (android.multiuser.Flags.fixGetUserPropertyCache() && userId < 0) {
+ throw new IllegalArgumentException("Cannot access properties for user " + userId);
+ }
+ return mUserPropertiesCache.query(userId);
}
/**
@@ -5663,6 +5668,33 @@ public class UserManager {
}
}
+ private static final String CACHE_KEY_QUIET_MODE_ENABLED_PROPERTY =
+ PropertyInvalidatedCache.createPropertyName(
+ PropertyInvalidatedCache.MODULE_SYSTEM, "quiet_mode_enabled");
+
+ private final PropertyInvalidatedCache<Integer, Boolean> mQuietModeEnabledCache =
+ new PropertyInvalidatedCache<Integer, Boolean>(
+ 32, CACHE_KEY_QUIET_MODE_ENABLED_PROPERTY) {
+ @Override
+ public Boolean recompute(Integer query) {
+ try {
+ return mService.isQuietModeEnabled(query);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+ @Override
+ public boolean bypass(Integer query) {
+ return query < 0;
+ }
+ };
+
+
+ /** @hide */
+ public static final void invalidateQuietModeEnabledCache() {
+ PropertyInvalidatedCache.invalidateCache(CACHE_KEY_QUIET_MODE_ENABLED_PROPERTY);
+ }
+
/**
* Returns whether the given profile is in quiet mode or not.
*
@@ -5670,6 +5702,13 @@ public class UserManager {
* @return true if the profile is in quiet mode, false otherwise.
*/
public boolean isQuietModeEnabled(UserHandle userHandle) {
+ if (android.multiuser.Flags.cacheQuietModeState()){
+ final int userId = userHandle.getIdentifier();
+ if (userId < 0) {
+ return false;
+ }
+ return mQuietModeEnabledCache.query(userId);
+ }
try {
return mService.isQuietModeEnabled(userHandle.getIdentifier());
} catch (RemoteException re) {
diff --git a/core/java/android/security/flags.aconfig b/core/java/android/security/flags.aconfig
index 3954bc2318cb..f6f0eff918e3 100644
--- a/core/java/android/security/flags.aconfig
+++ b/core/java/android/security/flags.aconfig
@@ -92,3 +92,10 @@ flag {
description: "Add a dump capability for attestation_verification service"
bug: "335498868"
}
+
+flag {
+ name: "should_trust_manager_listen_for_primary_auth"
+ namespace: "biometrics"
+ description: "Causes TrustManagerService to listen for credential attempts and ignore reports from upstream"
+ bug: "323086607"
+}
diff --git a/core/java/android/service/chooser/flags.aconfig b/core/java/android/service/chooser/flags.aconfig
index 82c16138f967..1f1a35117f72 100644
--- a/core/java/android/service/chooser/flags.aconfig
+++ b/core/java/android/service/chooser/flags.aconfig
@@ -2,14 +2,6 @@ package: "android.service.chooser"
container: "system"
flag {
- name: "enable_sharesheet_metadata_extra"
- is_exported: true
- namespace: "intentresolver"
- description: "This flag enables sharesheet metadata to be displayed to users."
- bug: "318942069"
-}
-
-flag {
name: "chooser_payload_toggling"
is_exported: true
namespace: "intentresolver"
diff --git a/core/java/android/tracing/flags.aconfig b/core/java/android/tracing/flags.aconfig
index be60c2504f38..04dba462bc1f 100644
--- a/core/java/android/tracing/flags.aconfig
+++ b/core/java/android/tracing/flags.aconfig
@@ -46,3 +46,11 @@ flag {
is_fixed_read_only: true
bug: "323165543"
}
+
+flag {
+ name: "client_side_proto_logging"
+ namespace: "windowing_tools"
+ description: "Add support for client side protologging"
+ is_fixed_read_only: true
+ bug: "352538294"
+}
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index cb5a885bd0a0..e5be53191e9e 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -53,6 +53,7 @@ import android.view.IWallpaperVisibilityListener;
import android.view.IWindow;
import android.view.IWindowSession;
import android.view.IWindowSessionCallback;
+import android.view.KeyboardShortcutGroup;
import android.view.KeyEvent;
import android.view.InputEvent;
import android.view.InsetsState;
@@ -1095,4 +1096,11 @@ interface IWindowManager
boolean transferTouchGesture(in InputTransferToken transferFromToken,
in InputTransferToken transferToToken);
+
+ /**
+ * Request the application launch keyboard shortcuts the system has defined.
+ *
+ * @param deviceId The id of the {@link InputDevice} that will handle the shortcut.
+ */
+ KeyboardShortcutGroup getApplicationLaunchKeyboardShortcuts(int deviceId);
}
diff --git a/core/java/android/view/InsetsFrameProvider.java b/core/java/android/view/InsetsFrameProvider.java
index fe98faba98c3..075571cb2890 100644
--- a/core/java/android/view/InsetsFrameProvider.java
+++ b/core/java/android/view/InsetsFrameProvider.java
@@ -162,6 +162,12 @@ public class InsetsFrameProvider implements Parcelable {
return mSource;
}
+ /** Set the flags of this provider. */
+ public InsetsFrameProvider setFlags(@Flags int flags) {
+ mFlags = flags;
+ return this;
+ }
+
public InsetsFrameProvider setFlags(@Flags int flags, @Flags int mask) {
mFlags = (mFlags & ~mask) | (flags & mask);
return this;
diff --git a/core/java/android/view/KeyboardShortcutGroup.aidl b/core/java/android/view/KeyboardShortcutGroup.aidl
new file mode 100644
index 000000000000..6f219dbda7ef
--- /dev/null
+++ b/core/java/android/view/KeyboardShortcutGroup.aidl
@@ -0,0 +1,3 @@
+package android.view;
+
+@JavaOnlyStableParcelable parcelable KeyboardShortcutGroup;
diff --git a/core/java/android/view/KeyboardShortcutInfo.java b/core/java/android/view/KeyboardShortcutInfo.java
index 3f6fd646994c..3f49bf3380c1 100644
--- a/core/java/android/view/KeyboardShortcutInfo.java
+++ b/core/java/android/view/KeyboardShortcutInfo.java
@@ -81,12 +81,29 @@ public final class KeyboardShortcutInfo implements Parcelable {
* {@link KeyEvent#META_SYM_ON}.
*/
public KeyboardShortcutInfo(CharSequence label, char baseCharacter, int modifiers) {
+ this(label, null, baseCharacter, modifiers);
+ }
+
+ /**
+ * @param label The label that identifies the action performed by this shortcut.
+ * @param icon An icon that identifies the action performed by this shortcut.
+ * @param baseCharacter The character that triggers the shortcut.
+ * @param modifiers The set of modifiers that, combined with the key, trigger the shortcut.
+ * These should be a combination of {@link KeyEvent#META_CTRL_ON},
+ * {@link KeyEvent#META_SHIFT_ON}, {@link KeyEvent#META_META_ON},
+ * {@link KeyEvent#META_ALT_ON}, {@link KeyEvent#META_FUNCTION_ON} and
+ * {@link KeyEvent#META_SYM_ON}.
+ *
+ * @hide
+ */
+ public KeyboardShortcutInfo(
+ CharSequence label, @Nullable Icon icon, char baseCharacter, int modifiers) {
mLabel = label;
checkArgument(baseCharacter != MIN_VALUE);
mBaseCharacter = baseCharacter;
mKeycode = KeyEvent.KEYCODE_UNKNOWN;
mModifiers = modifiers;
- mIcon = null;
+ mIcon = icon;
}
private KeyboardShortcutInfo(Parcel source) {
diff --git a/core/java/android/view/SurfaceControlRegistry.java b/core/java/android/view/SurfaceControlRegistry.java
index 117b200d054e..a806bd226c36 100644
--- a/core/java/android/view/SurfaceControlRegistry.java
+++ b/core/java/android/view/SurfaceControlRegistry.java
@@ -295,16 +295,7 @@ public class SurfaceControlRegistry {
}
sCallStackDebuggingInitialized = true;
- sCallStackDebuggingMatchCall =
- SystemProperties.get("persist.wm.debug.sc.tx.log_match_call", null)
- .toLowerCase();
- sCallStackDebuggingMatchName =
- SystemProperties.get("persist.wm.debug.sc.tx.log_match_name", null)
- .toLowerCase();
- sLogAllTxCallsOnApply = sCallStackDebuggingMatchCall.contains("apply");
- // Only enable stack debugging if any of the match filters are set
- sCallStackDebuggingEnabled = !sCallStackDebuggingMatchCall.isEmpty()
- || !sCallStackDebuggingMatchName.isEmpty();
+ updateCallStackDebuggingParams();
if (sCallStackDebuggingEnabled) {
Log.d(TAG, "Enabling transaction call stack debugging:"
+ " matchCall=" + sCallStackDebuggingMatchCall
@@ -325,6 +316,11 @@ public class SurfaceControlRegistry {
final void checkCallStackDebugging(@NonNull String call,
@Nullable SurfaceControl.Transaction tx, @Nullable SurfaceControl sc,
@Nullable String details) {
+
+ if (sCallStackDebuggingInitialized && sCallStackDebuggingEnabled) {
+ updateCallStackDebuggingParams();
+ }
+
if (!sCallStackDebuggingEnabled) {
return;
}
@@ -356,6 +352,22 @@ public class SurfaceControlRegistry {
}
/**
+ * Updates the call stack debugging params from the system properties.
+ */
+ private static void updateCallStackDebuggingParams() {
+ sCallStackDebuggingMatchCall =
+ SystemProperties.get("persist.wm.debug.sc.tx.log_match_call", null)
+ .toLowerCase();
+ sCallStackDebuggingMatchName =
+ SystemProperties.get("persist.wm.debug.sc.tx.log_match_name", null)
+ .toLowerCase();
+ sLogAllTxCallsOnApply = sCallStackDebuggingMatchCall.contains("apply");
+ // Only enable stack debugging if any of the match filters are set
+ sCallStackDebuggingEnabled = !sCallStackDebuggingMatchCall.isEmpty()
+ || !sCallStackDebuggingMatchName.isEmpty();
+ }
+
+ /**
* Tests whether the given surface control name/method call matches the filters set for the
* call stack debugging.
*/
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index f77e21935f05..88d7a834ff53 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -22,6 +22,7 @@ import static android.os.Trace.TRACE_TAG_VIEW;
import static android.service.autofill.Flags.FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION;
import static android.view.ContentInfo.SOURCE_DRAG_AND_DROP;
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;
@@ -19638,7 +19639,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
public final void setLeft(int left) {
if (left != mLeft) {
- mPrivateFlags4 |= PFLAG4_HAS_MOVED;
final boolean matrixIsIdentity = hasIdentityMatrix();
if (matrixIsIdentity) {
if (mAttachInfo != null) {
@@ -25592,6 +25592,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
? FRAME_RATE_CATEGORY_NORMAL : FRAME_RATE_CATEGORY_HIGH;
mSizeBasedFrameRateCategoryAndReason = category | FRAME_RATE_CATEGORY_REASON_LARGE;
}
+ mPrivateFlags4 |= PFLAG4_HAS_MOVED;
}
onSizeChanged(newWidth, newHeight, oldWidth, oldHeight);
@@ -33905,8 +33906,24 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @hide
*/
protected int calculateFrameRateCategory() {
+ ViewRootImpl viewRootImpl = getViewRootImpl();
+ ViewParent parent = mParent;
+ boolean isInputMethodWindowType =
+ viewRootImpl.mWindowAttributes.type == TYPE_INPUT_METHOD;
+
+ // boost frame rate when the position or the size changed.
+ if (((mPrivateFlags4 & (PFLAG4_HAS_MOVED | PFLAG4_HAS_DRAWN)) == (
+ PFLAG4_HAS_MOVED | PFLAG4_HAS_DRAWN) || mLastFrameLeft != mLeft
+ || mLastFrameTop != mTop)
+ && viewRootImpl.shouldCheckFrameRateCategory()
+ && parent instanceof View
+ && ((View) parent).mFrameContentVelocity <= 0
+ && !isInputMethodWindowType) {
+
+ return FRAME_RATE_CATEGORY_HIGH_HINT | FRAME_RATE_CATEGORY_REASON_BOOST;
+ }
int category;
- switch (getViewRootImpl().intermittentUpdateState()) {
+ switch (viewRootImpl.intermittentUpdateState()) {
case ViewRootImpl.INTERMITTENT_STATE_INTERMITTENT -> {
if (!sToolkitFrameRateBySizeReadOnlyFlagValue) {
category = FRAME_RATE_CATEGORY_NORMAL;
@@ -33940,66 +33957,23 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
float velocity = mFrameContentVelocity;
final float frameRate = mPreferredFrameRate;
- ViewParent parent = mParent;
- boolean isInputMethodWindowType = false;
- if (mAttachInfo != null && mAttachInfo.mViewRootImpl != null) {
- isInputMethodWindowType =
- mAttachInfo.mViewRootImpl.mWindowAttributes.type == TYPE_INPUT_METHOD;
- }
- if (velocity <= 0 && Float.isNaN(frameRate)) {
- // The most common case is when nothing is set, so this special case is called
- // often.
- if (mAttachInfo.mViewVelocityApi
- && ((mPrivateFlags4 & (PFLAG4_HAS_MOVED | PFLAG4_HAS_DRAWN)) == (
- PFLAG4_HAS_MOVED | PFLAG4_HAS_DRAWN) || mLastFrameLeft != mLeft
- || mLastFrameTop != mTop)
- && viewRootImpl.shouldCheckFrameRate(false)
- && parent instanceof View
- && ((View) parent).mFrameContentVelocity <= 0
- && !isInputMethodWindowType) {
- viewRootImpl.votePreferredFrameRate(MAX_FRAME_RATE, FRAME_RATE_COMPATIBILITY_GTE);
- }
- if (viewRootImpl.shouldCheckFrameRateCategory()) {
- int frameRateCategory = calculateFrameRateCategory();
- int category = frameRateCategory & ~FRAME_RATE_CATEGORY_REASON_MASK;
- int reason = frameRateCategory & FRAME_RATE_CATEGORY_REASON_MASK;
- viewRootImpl.votePreferredFrameRateCategory(category, reason, this);
- mLastFrameRateCategory = frameRateCategory;
- }
- mLastFrameLeft = mLeft;
- mLastFrameTop = mTop;
- return;
- }
- if (viewRootImpl.shouldCheckFrameRate(frameRate > 0f)) {
+
+ if (viewRootImpl.shouldCheckFrameRate(frameRate > 0f)
+ && (frameRate > 0 || (mAttachInfo.mViewVelocityApi && velocity > 0f))) {
float velocityFrameRate = 0f;
- if (mAttachInfo.mViewVelocityApi) {
- if (velocity < 0f
- && ((mPrivateFlags4 & (PFLAG4_HAS_MOVED | PFLAG4_HAS_DRAWN)) == (
- PFLAG4_HAS_MOVED | PFLAG4_HAS_DRAWN) || mLastFrameLeft != mLeft
- || mLastFrameTop != mTop)
- && mParent instanceof View
- && ((View) mParent).mFrameContentVelocity <= 0
- && !isInputMethodWindowType
- ) {
- // This current calculation is very simple. If something on the screen
- // moved, then it votes for the highest velocity.
- velocityFrameRate = MAX_FRAME_RATE;
- } else if (velocity > 0f) {
- velocityFrameRate = convertVelocityToFrameRate(velocity);
- }
- }
- if (velocityFrameRate > 0f || frameRate > 0f) {
- int compatibility;
- float frameRateToSet;
- if (frameRate >= velocityFrameRate) {
- compatibility = FRAME_RATE_COMPATIBILITY_FIXED_SOURCE;
- frameRateToSet = frameRate;
- } else {
- compatibility = FRAME_RATE_COMPATIBILITY_GTE;
- frameRateToSet = velocityFrameRate;
- }
- viewRootImpl.votePreferredFrameRate(frameRateToSet, compatibility);
+ if (mAttachInfo.mViewVelocityApi && velocity > 0f) {
+ velocityFrameRate = convertVelocityToFrameRate(velocity);
+ }
+ int compatibility;
+ float frameRateToSet;
+ if (frameRate >= velocityFrameRate) {
+ compatibility = FRAME_RATE_COMPATIBILITY_FIXED_SOURCE;
+ frameRateToSet = frameRate;
+ } else {
+ compatibility = FRAME_RATE_COMPATIBILITY_GTE;
+ frameRateToSet = velocityFrameRate;
}
+ viewRootImpl.votePreferredFrameRate(frameRateToSet, compatibility);
}
if (viewRootImpl.shouldCheckFrameRateCategory()) {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 07cbaa9c905f..e5b17c8d1001 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -128,8 +128,8 @@ import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodCl
import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
import static com.android.text.flags.Flags.disableHandwritingInitiatorForIme;
-import static com.android.window.flags.Flags.activityWindowInfoFlag;
import static com.android.window.flags.Flags.enableBufferTransformHintFromDisplay;
+import static com.android.window.flags.Flags.enableCaptionCompatInsetForceConsumption;
import static com.android.window.flags.Flags.insetsControlChangedItem;
import static com.android.window.flags.Flags.insetsControlSeq;
import static com.android.window.flags.Flags.setScPropertiesInClient;
@@ -1373,9 +1373,6 @@ public final class ViewRootImpl implements ViewParent,
*/
public void setActivityConfigCallback(@Nullable ActivityConfigCallback callback) {
mActivityConfigCallback = callback;
- if (!activityWindowInfoFlag()) {
- return;
- }
if (callback == null) {
mPendingActivityWindowInfo = null;
mLastReportedActivityWindowInfo = null;
@@ -3189,7 +3186,9 @@ public final class ViewRootImpl implements ViewParent,
inOutParams.privateFlags &= ~PRIVATE_FLAG_FIT_INSETS_CONTROLLED;
}
- private void controlInsetsForCompatibility(WindowManager.LayoutParams params) {
+ /** Updates the {@link InsetsType}s to hide or show based on layout params. */
+ @VisibleForTesting
+ public void controlInsetsForCompatibility(WindowManager.LayoutParams params) {
final int sysUiVis = params.systemUiVisibility | params.subtreeSystemUiVisibility;
final int flags = params.flags;
final boolean matchParent = params.width == MATCH_PARENT && params.height == MATCH_PARENT;
@@ -3200,6 +3199,9 @@ public final class ViewRootImpl implements ViewParent,
|| ((flags & FLAG_FULLSCREEN) != 0 && matchParent && nonAttachedAppWindow);
final boolean navWasHiddenByFlags = (mTypesHiddenByFlags & Type.navigationBars()) != 0;
final boolean navIsHiddenByFlags = (sysUiVis & SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0;
+ final boolean captionWasHiddenByFlags = (mTypesHiddenByFlags & Type.captionBar()) != 0;
+ final boolean captionIsHiddenByFlags = (sysUiVis & SYSTEM_UI_FLAG_FULLSCREEN) != 0
+ || ((flags & FLAG_FULLSCREEN) != 0 && matchParent && nonAttachedAppWindow);
@InsetsType int typesToHide = 0;
@InsetsType int typesToShow = 0;
@@ -3213,6 +3215,13 @@ public final class ViewRootImpl implements ViewParent,
} else if (!navIsHiddenByFlags && navWasHiddenByFlags) {
typesToShow |= Type.navigationBars();
}
+ if (captionIsHiddenByFlags && !captionWasHiddenByFlags
+ && enableCaptionCompatInsetForceConsumption()) {
+ typesToHide |= Type.captionBar();
+ } else if (!captionIsHiddenByFlags && captionWasHiddenByFlags
+ && enableCaptionCompatInsetForceConsumption()) {
+ typesToShow |= Type.captionBar();
+ }
if (typesToHide != 0) {
getInsetsController().hide(typesToHide);
}
@@ -4424,6 +4433,8 @@ public final class ViewRootImpl implements ViewParent,
}
mFrameRateCategoryHighCount = mFrameRateCategoryHighCount > 0
? mFrameRateCategoryHighCount - 1 : mFrameRateCategoryHighCount;
+ mFrameRateCategoryHighHintCount = mFrameRateCategoryHighHintCount > 0
+ ? mFrameRateCategoryHighHintCount - 1 : mFrameRateCategoryHighHintCount;
mFrameRateCategoryNormalCount = mFrameRateCategoryNormalCount > 0
? mFrameRateCategoryNormalCount - 1 : mFrameRateCategoryNormalCount;
mFrameRateCategoryLowCount = mFrameRateCategoryLowCount > 0
@@ -9345,7 +9356,7 @@ public final class ViewRootImpl implements ViewParent,
onClientWindowFramesChanged(mTmpFrames);
- if (activityWindowInfoFlag() && mPendingActivityWindowInfo != null) {
+ if (mPendingActivityWindowInfo != null) {
final ActivityWindowInfo outInfo = mRelayoutResult.activityWindowInfo;
if (outInfo != null) {
mPendingActivityWindowInfo.set(outInfo);
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 18006bb7866a..14978ede88cc 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1668,6 +1668,15 @@ public interface WindowManager extends ViewManager {
public void requestAppKeyboardShortcuts(final KeyboardShortcutsReceiver receiver, int deviceId);
/**
+ * Request the application launch keyboard shortcuts the system has defined.
+ *
+ * @param deviceId The id of the {@link InputDevice} that will handle the shortcut.
+ *
+ * @hide
+ */
+ KeyboardShortcutGroup getApplicationLaunchKeyboardShortcuts(int deviceId);
+
+ /**
* Request for ime's keyboard shortcuts to be retrieved asynchronously.
*
* @param receiver The callback to be triggered when the result is ready.
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index b667427fd2c5..330e46af6381 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -237,6 +237,16 @@ public final class WindowManagerImpl implements WindowManager {
}
@Override
+ public KeyboardShortcutGroup getApplicationLaunchKeyboardShortcuts(int deviceId) {
+ try {
+ return WindowManagerGlobal.getWindowManagerService()
+ .getApplicationLaunchKeyboardShortcuts(deviceId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ @Override
public void requestImeKeyboardShortcuts(
final KeyboardShortcutsReceiver receiver, int deviceId) {
IResultReceiver resultReceiver = new IResultReceiver.Stub() {
diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java
index 11ee286652a1..098f65575928 100644
--- a/core/java/android/view/inputmethod/InputMethodInfo.java
+++ b/core/java/android/view/inputmethod/InputMethodInfo.java
@@ -92,7 +92,7 @@ public final class InputMethodInfo implements Parcelable {
*
* @see #createImeLanguageSettingsActivityIntent()
*/
- @FlaggedApi(android.view.inputmethod.Flags.FLAG_IME_SWITCHER_REVAMP)
+ @FlaggedApi(android.view.inputmethod.Flags.FLAG_IME_SWITCHER_REVAMP_API)
public static final String ACTION_IME_LANGUAGE_SETTINGS =
"android.view.inputmethod.action.IME_LANGUAGE_SETTINGS";
@@ -298,7 +298,7 @@ public final class InputMethodInfo implements Parcelable {
com.android.internal.R.styleable.InputMethod);
settingsActivityComponent = sa.getString(
com.android.internal.R.styleable.InputMethod_settingsActivity);
- if (Flags.imeSwitcherRevamp()) {
+ if (Flags.imeSwitcherRevampApi()) {
languageSettingsActivityComponent = sa.getString(
com.android.internal.R.styleable.InputMethod_languageSettingsActivity);
}
@@ -888,7 +888,7 @@ public final class InputMethodInfo implements Parcelable {
*
* @attr ref R.styleable#InputMethod_languageSettingsActivity
*/
- @FlaggedApi(android.view.inputmethod.Flags.FLAG_IME_SWITCHER_REVAMP)
+ @FlaggedApi(android.view.inputmethod.Flags.FLAG_IME_SWITCHER_REVAMP_API)
@Nullable
public Intent createImeLanguageSettingsActivityIntent() {
if (TextUtils.isEmpty(mLanguageSettingsActivityName)) {
diff --git a/core/java/android/view/inputmethod/flags.aconfig b/core/java/android/view/inputmethod/flags.aconfig
index 56e5bcf79933..e294ee2d3a91 100644
--- a/core/java/android/view/inputmethod/flags.aconfig
+++ b/core/java/android/view/inputmethod/flags.aconfig
@@ -82,6 +82,15 @@ flag {
}
flag {
+ name: "ime_switcher_revamp_api"
+ is_exported: true
+ namespace: "input_method"
+ description: "Feature flag for APIs for revamping the Input Method Switcher menu"
+ bug: "311791923"
+ is_fixed_read_only: true
+}
+
+flag {
name: "initiation_without_input_connection"
namespace: "input_method"
description: "Feature flag for initiating handwriting without InputConnection"
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index 10344792eee2..c53a0e158dea 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -36,6 +36,7 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.Trace;
+import android.os.UserHandle;
import android.text.TextUtils;
import android.util.AndroidRuntimeException;
import android.util.ArraySet;
@@ -339,10 +340,10 @@ public final class WebViewFactory {
if (sProviderInstance != null) return sProviderInstance;
sTimestamps.mWebViewLoadStart = SystemClock.uptimeMillis();
- final int uid = android.os.Process.myUid();
- if (uid == android.os.Process.ROOT_UID || uid == android.os.Process.SYSTEM_UID
- || uid == android.os.Process.PHONE_UID || uid == android.os.Process.NFC_UID
- || uid == android.os.Process.BLUETOOTH_UID) {
+ final int appId = UserHandle.getAppId(android.os.Process.myUid());
+ if (appId == android.os.Process.ROOT_UID || appId == android.os.Process.SYSTEM_UID
+ || appId == android.os.Process.PHONE_UID || appId == android.os.Process.NFC_UID
+ || appId == android.os.Process.BLUETOOTH_UID) {
throw new UnsupportedOperationException(
"For security reasons, WebView is not allowed in privileged processes");
}
diff --git a/core/java/android/window/BackProgressAnimator.java b/core/java/android/window/BackProgressAnimator.java
index d28500c0a1ea..12d4ab8bc963 100644
--- a/core/java/android/window/BackProgressAnimator.java
+++ b/core/java/android/window/BackProgressAnimator.java
@@ -16,12 +16,15 @@
package android.window;
+import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.util.FloatProperty;
import android.util.TimeUtils;
import android.view.Choreographer;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.dynamicanimation.animation.DynamicAnimation;
import com.android.internal.dynamicanimation.animation.FlingAnimation;
import com.android.internal.dynamicanimation.animation.FloatValueHolder;
@@ -210,7 +213,8 @@ public class BackProgressAnimator implements DynamicAnimation.OnAnimationUpdateL
}
/** Returns true if the back animation is in progress. */
- boolean isBackAnimationInProgress() {
+ @VisibleForTesting(visibility = PACKAGE)
+ public boolean isBackAnimationInProgress() {
return mBackAnimationInProgress;
}
diff --git a/core/java/android/window/ITaskFragmentOrganizerController.aidl b/core/java/android/window/ITaskFragmentOrganizerController.aidl
index 4706dfd1a76c..2c64b8ed456d 100644
--- a/core/java/android/window/ITaskFragmentOrganizerController.aidl
+++ b/core/java/android/window/ITaskFragmentOrganizerController.aidl
@@ -39,19 +39,6 @@ interface ITaskFragmentOrganizerController {
void unregisterOrganizer(in ITaskFragmentOrganizer organizer);
/**
- * Registers remote animations per transition type for the organizer. It will override the
- * animations if the transition only contains windows that belong to the organized
- * TaskFragments in the given Task.
- */
- void registerRemoteAnimations(in ITaskFragmentOrganizer organizer,
- in RemoteAnimationDefinition definition);
-
- /**
- * Unregisters remote animations per transition type for the organizer.
- */
- void unregisterRemoteAnimations(in ITaskFragmentOrganizer organizer);
-
- /**
* Checks if an activity organized by a {@link android.window.TaskFragmentOrganizer} and
* only occupies a portion of Task bounds.
*/
diff --git a/core/java/android/window/TaskFragmentOrganizer.java b/core/java/android/window/TaskFragmentOrganizer.java
index 461eab61e393..15f1258ccd69 100644
--- a/core/java/android/window/TaskFragmentOrganizer.java
+++ b/core/java/android/window/TaskFragmentOrganizer.java
@@ -32,7 +32,6 @@ import android.annotation.TestApi;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
-import android.view.RemoteAnimationDefinition;
import android.view.WindowManager;
import com.android.window.flags.Flags;
@@ -205,34 +204,6 @@ public class TaskFragmentOrganizer extends WindowOrganizer {
}
/**
- * Registers remote animations per transition type for the organizer. It will override the
- * animations if the transition only contains windows that belong to the organized
- * TaskFragments, and at least one of the transition window is embedded (not filling the Task).
- * @hide
- */
- @CallSuper
- public void registerRemoteAnimations(@NonNull RemoteAnimationDefinition definition) {
- try {
- getController().registerRemoteAnimations(mInterface, definition);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Unregisters remote animations per transition type for the organizer.
- * @hide
- */
- @CallSuper
- public void unregisterRemoteAnimations() {
- try {
- getController().unregisterRemoteAnimations(mInterface);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
* Notifies the server that the organizer has finished handling the given transaction. The
* server should apply the given {@link WindowContainerTransaction} for the necessary changes.
*
@@ -357,6 +328,7 @@ public class TaskFragmentOrganizer extends WindowOrganizer {
* only occupies a portion of Task bounds.
* @hide
*/
+ // TODO(b/287582673): cleanup
public boolean isActivityEmbedded(@NonNull IBinder activityToken) {
try {
return getController().isActivityEmbedded(activityToken);
diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java
index 8ded608b71e1..1083f64513b1 100644
--- a/core/java/android/window/TransitionInfo.java
+++ b/core/java/android/window/TransitionInfo.java
@@ -205,7 +205,7 @@ public final class TransitionInfo implements Parcelable {
FLAG_SYNC,
FLAG_CONFIG_AT_END,
FLAG_FIRST_CUSTOM
- })
+ }, flag = true)
public @interface ChangeFlags {}
private final @TransitionType int mType;
diff --git a/core/java/android/window/TransitionRequestInfo.java b/core/java/android/window/TransitionRequestInfo.java
index cc225767bd49..253337b553da 100644
--- a/core/java/android/window/TransitionRequestInfo.java
+++ b/core/java/android/window/TransitionRequestInfo.java
@@ -471,7 +471,7 @@ public final class TransitionRequestInfo implements Parcelable {
"pipTask = " + mPipTask + ", " +
"remoteTransition = " + mRemoteTransition + ", " +
"displayChange = " + mDisplayChange + ", " +
- "flags = " + mFlags + ", " +
+ "flags = " + Integer.toHexString(mFlags) + ", " +
"debugId = " + mDebugId +
" }";
}
diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java
index cd033caf4871..e9d77f8aaf80 100644
--- a/core/java/android/window/WindowContainerTransaction.java
+++ b/core/java/android/window/WindowContainerTransaction.java
@@ -42,6 +42,7 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.util.ArrayMap;
import android.view.InsetsFrameProvider;
+import android.view.InsetsSource;
import android.view.SurfaceControl;
import android.view.WindowInsets.Type.InsetsType;
@@ -714,14 +715,16 @@ public final class WindowContainerTransaction implements Parcelable {
@NonNull
public WindowContainerTransaction addInsetsSource(
@NonNull WindowContainerToken receiver,
- IBinder owner, int index, @InsetsType int type, Rect frame, Rect[] boundingRects) {
+ IBinder owner, int index, @InsetsType int type, Rect frame, Rect[] boundingRects,
+ @InsetsSource.Flags int flags) {
final HierarchyOp hierarchyOp =
new HierarchyOp.Builder(HierarchyOp.HIERARCHY_OP_TYPE_ADD_INSETS_FRAME_PROVIDER)
.setContainer(receiver.asBinder())
.setInsetsFrameProvider(new InsetsFrameProvider(owner, index, type)
.setSource(InsetsFrameProvider.SOURCE_ARBITRARY_RECTANGLE)
.setArbitraryRectangle(frame)
- .setBoundingRects(boundingRects))
+ .setBoundingRects(boundingRects)
+ .setFlags(flags))
.setInsetsFrameOwner(owner)
.build();
mHierarchyOps.add(hierarchyOp);
diff --git a/core/java/android/window/WindowOnBackInvokedDispatcher.java b/core/java/android/window/WindowOnBackInvokedDispatcher.java
index 9b87e2351e3f..7bbc3dbb29db 100644
--- a/core/java/android/window/WindowOnBackInvokedDispatcher.java
+++ b/core/java/android/window/WindowOnBackInvokedDispatcher.java
@@ -244,6 +244,7 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
// We should call onBackCancelled() when an active callback is removed from
// dispatcher.
sendCancelledIfInProgress(callback);
+ mHandler.post(mProgressAnimator::reset);
setTopOnBackInvokedCallback(getTopCallback());
}
}
diff --git a/core/java/android/window/flags/lse_desktop_experience.aconfig b/core/java/android/window/flags/lse_desktop_experience.aconfig
index 245c0e7c630c..1362f7bf9619 100644
--- a/core/java/android/window/flags/lse_desktop_experience.aconfig
+++ b/core/java/android/window/flags/lse_desktop_experience.aconfig
@@ -40,8 +40,8 @@ flag {
flag {
name: "enable_windowing_edge_drag_resize"
namespace: "lse_desktop_experience"
- description: "Enables edge drag resizing for all input sources"
- bug: "323383067"
+ description: "Enables edge drag resizing for stylus input (cursor is enabled by default)"
+ bug: "337782092"
}
flag {
@@ -150,8 +150,29 @@ flag {
}
flag {
+ name: "enable_caption_compat_inset_conversion"
+ namespace: "lse_desktop_experience"
+ description: "Enables compatibility mitigation for apps that don't support caption insets well"
+ bug: "316231589"
+}
+
+flag {
name: "enable_desktop_windowing_multi_instance_features"
namespace: "lse_desktop_experience"
description: "Whether to enable multi-instance support in desktop windowing."
bug: "336289597"
}
+
+flag {
+ name: "enable_desktop_windowing_back_navigation"
+ namespace: "lse_desktop_experience"
+ description: "Whether to enable back navigation treatment in desktop windowing."
+ bug: "350421096"
+}
+
+flag {
+ name: "enable_desktop_windowing_app_handle_education"
+ namespace: "lse_desktop_experience"
+ description: "Enables desktop windowing app handle education"
+ bug: "348208342"
+}
diff --git a/core/java/android/window/flags/windowing_frontend.aconfig b/core/java/android/window/flags/windowing_frontend.aconfig
index 6b2454568c29..5397e91bd249 100644
--- a/core/java/android/window/flags/windowing_frontend.aconfig
+++ b/core/java/android/window/flags/windowing_frontend.aconfig
@@ -141,6 +141,13 @@ flag {
}
flag {
+ name: "respect_non_top_visible_fixed_orientation"
+ namespace: "windowing_frontend"
+ description: "If top activity is not opaque, respect the fixed orientation of activity behind it"
+ bug: "283514860"
+}
+
+flag {
name: "insets_decoupled_configuration"
namespace: "windowing_frontend"
description: "Configuration decoupled from insets"
@@ -199,3 +206,22 @@ flag {
}
}
+flag {
+ name: "enforce_shell_thread_model"
+ namespace: "windowing_frontend"
+ description: "Crash the shell process if someone calls in from the wrong thread"
+ bug: "351189446"
+ is_fixed_read_only: true
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+flag {
+ name: "custom_animations_behind_translucent"
+ namespace: "windowing_frontend"
+ description: "A change can use its own layer parameters to animate behind a translucent activity"
+ bug: "327332488"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/core/java/com/android/internal/app/SuspendedAppActivity.java b/core/java/com/android/internal/app/SuspendedAppActivity.java
index 7a8a47e5f9fc..9d5704141c93 100644
--- a/core/java/com/android/internal/app/SuspendedAppActivity.java
+++ b/core/java/com/android/internal/app/SuspendedAppActivity.java
@@ -342,8 +342,8 @@ public class SuspendedAppActivity extends AlertActivity
.MODE_BACKGROUND_ACTIVITY_START_ALLOWED)
.toBundle();
try {
- mOnUnsuspend.sendIntent(this, 0, null, null, null, null,
- activityOptions);
+ mOnUnsuspend.sendIntent(this, 0, null, null, activityOptions,
+ null, null);
} catch (IntentSender.SendIntentException e) {
Slog.e(TAG, "Error while starting intent " + mOnUnsuspend, e);
}
diff --git a/core/java/com/android/internal/jank/Cuj.java b/core/java/com/android/internal/jank/Cuj.java
index 5c818f178739..3e6f18e8e24b 100644
--- a/core/java/com/android/internal/jank/Cuj.java
+++ b/core/java/com/android/internal/jank/Cuj.java
@@ -160,8 +160,13 @@ public class Cuj {
*/
public static final int CUJ_DESKTOP_MODE_RESIZE_WINDOW = 106;
- /** Track entering desktop mode interaction. */
- public static final int CUJ_DESKTOP_MODE_ENTER_MODE = 107;
+ /**
+ * Track entering desktop mode interaction via app handle drag.
+ *
+ * <p>Tracking starts when the app handle is dragged and
+ * finishes when the window animation to desktop ends after app handle release.
+ */
+ public static final int CUJ_DESKTOP_MODE_ENTER_MODE_APP_HANDLE_DRAG = 107;
/** Track exiting desktop mode interaction. */
public static final int CUJ_DESKTOP_MODE_EXIT_MODE = 108;
@@ -175,14 +180,22 @@ public class Cuj {
/** Track launching a dialog from a status bar chip. */
public static final int CUJ_STATUS_BAR_LAUNCH_DIALOG_FROM_CHIP = 111;
+ /**
+ * Track entering desktop mode interaction via app handle menu.
+ *
+ * <p>Tracking starts after windowing mode option in the app handle menu is clicked and
+ * finishes when the window animation to desktop ends.
+ */
+ public static final int CUJ_DESKTOP_MODE_ENTER_MODE_APP_HANDLE_MENU = 112;
+
/** Track Launcher Keyboard Quick Switch View opening animation */
- public static final int CUJ_LAUNCHER_KEYBOARD_QUICK_SWITCH_OPEN = 112;
+ public static final int CUJ_LAUNCHER_KEYBOARD_QUICK_SWITCH_OPEN = 113;
/** Track Launcher Keyboard Quick Switch View closing animation */
- public static final int CUJ_LAUNCHER_KEYBOARD_QUICK_SWITCH_CLOSE = 113;
+ public static final int CUJ_LAUNCHER_KEYBOARD_QUICK_SWITCH_CLOSE = 114;
/** Track launching an app through the Launcher Keyboard Quick Switch View */
- public static final int CUJ_LAUNCHER_KEYBOARD_QUICK_SWITCH_APP_LAUNCH = 114;
+ public static final int CUJ_LAUNCHER_KEYBOARD_QUICK_SWITCH_APP_LAUNCH = 115;
// 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_KEYBOARD_QUICK_SWITCH_APP_LAUNCH;
@@ -284,7 +297,8 @@ public class Cuj {
CUJ_DESKTOP_MODE_MAXIMIZE_WINDOW,
CUJ_FOLD_ANIM,
CUJ_DESKTOP_MODE_RESIZE_WINDOW,
- CUJ_DESKTOP_MODE_ENTER_MODE,
+ CUJ_DESKTOP_MODE_ENTER_MODE_APP_HANDLE_DRAG,
+ CUJ_DESKTOP_MODE_ENTER_MODE_APP_HANDLE_MENU,
CUJ_DESKTOP_MODE_EXIT_MODE,
CUJ_DESKTOP_MODE_MINIMIZE_WINDOW,
CUJ_DESKTOP_MODE_DRAG_WINDOW,
@@ -400,7 +414,8 @@ public class Cuj {
CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_DESKTOP_MODE_MAXIMIZE_WINDOW] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__DESKTOP_MODE_MAXIMIZE_WINDOW;
CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_FOLD_ANIM] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__FOLD_ANIM;
CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_DESKTOP_MODE_RESIZE_WINDOW] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__DESKTOP_MODE_RESIZE_WINDOW;
- CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_DESKTOP_MODE_ENTER_MODE] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__DESKTOP_MODE_ENTER_MODE;
+ CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_DESKTOP_MODE_ENTER_MODE_APP_HANDLE_DRAG] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__DESKTOP_MODE_ENTER_MODE_APP_HANDLE_DRAG;
+ CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_DESKTOP_MODE_ENTER_MODE_APP_HANDLE_MENU] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__DESKTOP_MODE_ENTER_MODE_APP_HANDLE_MENU;
CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_DESKTOP_MODE_EXIT_MODE] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__DESKTOP_MODE_EXIT_MODE;
CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_DESKTOP_MODE_MINIMIZE_WINDOW] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__DESKTOP_MODE_MINIMIZE_WINDOW;
CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_DESKTOP_MODE_DRAG_WINDOW] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__DESKTOP_MODE_DRAG_WINDOW;
@@ -616,8 +631,10 @@ public class Cuj {
return "FOLD_ANIM";
case CUJ_DESKTOP_MODE_RESIZE_WINDOW:
return "DESKTOP_MODE_RESIZE_WINDOW";
- case CUJ_DESKTOP_MODE_ENTER_MODE:
- return "DESKTOP_MODE_ENTER_MODE";
+ case CUJ_DESKTOP_MODE_ENTER_MODE_APP_HANDLE_DRAG:
+ return "DESKTOP_MODE_ENTER_MODE_APP_HANDLE_DRAG";
+ case CUJ_DESKTOP_MODE_ENTER_MODE_APP_HANDLE_MENU:
+ return "DESKTOP_MODE_ENTER_MODE_APP_HANDLE_MENU";
case CUJ_DESKTOP_MODE_EXIT_MODE:
return "DESKTOP_MODE_EXIT_MODE";
case CUJ_DESKTOP_MODE_MINIMIZE_WINDOW:
@@ -627,11 +644,11 @@ public class Cuj {
case CUJ_STATUS_BAR_LAUNCH_DIALOG_FROM_CHIP:
return "STATUS_BAR_LAUNCH_DIALOG_FROM_CHIP";
case CUJ_LAUNCHER_KEYBOARD_QUICK_SWITCH_OPEN:
- return "CUJ_LAUNCHER_KEYBOARD_QUICK_SWITCH_OPEN";
+ return "LAUNCHER_KEYBOARD_QUICK_SWITCH_OPEN";
case CUJ_LAUNCHER_KEYBOARD_QUICK_SWITCH_CLOSE:
- return "CUJ_LAUNCHER_KEYBOARD_QUICK_SWITCH_CLOSE";
+ return "LAUNCHER_KEYBOARD_QUICK_SWITCH_CLOSE";
case CUJ_LAUNCHER_KEYBOARD_QUICK_SWITCH_APP_LAUNCH:
- return "CUJ_LAUNCHER_KEYBOARD_QUICK_SWITCH_APP_LAUNCH";
+ return "LAUNCHER_KEYBOARD_QUICK_SWITCH_APP_LAUNCH";
}
return "UNKNOWN";
}
diff --git a/core/java/com/android/internal/os/flags.aconfig b/core/java/com/android/internal/os/flags.aconfig
index 30fa4f1a472a..2ad665181e70 100644
--- a/core/java/com/android/internal/os/flags.aconfig
+++ b/core/java/com/android/internal/os/flags.aconfig
@@ -12,7 +12,7 @@ flag {
flag {
name: "use_transaction_codes_for_unknown_methods"
- namespace: "dropbox"
+ namespace: "stability"
description: "Use transaction codes when the method names is unknown"
bug: "350041302"
is_fixed_read_only: true
diff --git a/core/java/com/android/internal/pm/pkg/component/AconfigFlags.java b/core/java/com/android/internal/pm/pkg/component/AconfigFlags.java
index f306b0b02677..b873175451e1 100644
--- a/core/java/com/android/internal/pm/pkg/component/AconfigFlags.java
+++ b/core/java/com/android/internal/pm/pkg/component/AconfigFlags.java
@@ -60,7 +60,13 @@ public class AconfigFlags {
"/product/etc/aconfig_flags.pb",
"/vendor/etc/aconfig_flags.pb");
+ public enum Permission {
+ READ_WRITE,
+ READ_ONLY
+ }
+
private final ArrayMap<String, Boolean> mFlagValues = new ArrayMap<>();
+ private final ArrayMap<String, Permission> mFlagPermissions = new ArrayMap<>();
public AconfigFlags() {
if (!Flags.manifestFlagging()) {
@@ -184,6 +190,12 @@ public class AconfigFlags {
Slog.v(LOG_TAG, "Read Aconfig default flag value "
+ flagPackageAndName + " = " + flagValue);
mFlagValues.put(flagPackageAndName, flagValue);
+
+ Permission permission = flag.permission == Aconfig.READ_ONLY
+ ? Permission.READ_ONLY
+ : Permission.READ_WRITE;
+
+ mFlagPermissions.put(flagPackageAndName, permission);
}
}
@@ -200,6 +212,17 @@ public class AconfigFlags {
}
/**
+ * Get the flag permission, or null if the flag doesn't exist.
+ * @param flagPackageAndName Full flag name formatted as 'package.flag'
+ * @return the current permission of the given Aconfig flag, or null if there is no such flag
+ */
+ @Nullable
+ public Permission getFlagPermission(@NonNull String flagPackageAndName) {
+ Permission permission = mFlagPermissions.get(flagPackageAndName);
+ return permission;
+ }
+
+ /**
* Check if the element in {@code parser} should be skipped because of the feature flag.
* @param parser XML parser object currently parsing an element
* @return true if the element is disabled because of its feature flag
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 63ff598bae61..87e22ed42cbd 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -109,6 +109,7 @@ import com.android.internal.view.menu.MenuHelper;
import com.android.internal.widget.ActionBarContextView;
import com.android.internal.widget.BackgroundFallback;
import com.android.internal.widget.floatingtoolbar.FloatingToolbar;
+import com.android.window.flags.Flags;
import java.util.List;
import java.util.function.Consumer;
@@ -1193,7 +1194,8 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
// If we should always consume system bars, only consume that if the app wanted to go to
// fullscreen, as otherwise we can expect the app to handle it.
boolean fullscreen = (sysUiVisibility & SYSTEM_UI_FLAG_FULLSCREEN) != 0
- || (attrs.flags & FLAG_FULLSCREEN) != 0
+ || (attrs.flags & FLAG_FULLSCREEN) != 0;
+ final boolean hideStatusBar = fullscreen
|| (requestedVisibleTypes & WindowInsets.Type.statusBars()) == 0;
boolean consumingStatusBar =
((sysUiVisibility & SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) == 0
@@ -1203,9 +1205,20 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
&& mForceWindowDrawsBarBackgrounds
&& mLastTopInset != 0)
|| ((mLastForceConsumingTypes & WindowInsets.Type.statusBars()) != 0
- && fullscreen);
+ && hideStatusBar);
- int consumedTop = consumingStatusBar ? mLastTopInset : 0;
+ final boolean hideCaptionBar = fullscreen
+ || (requestedVisibleTypes & WindowInsets.Type.captionBar()) == 0;
+ final boolean consumingCaptionBar =
+ ((mLastForceConsumingTypes & WindowInsets.Type.captionBar()) != 0
+ && hideCaptionBar);
+
+ final int consumedTop;
+ if (Flags.enableCaptionCompatInsetForceConsumption()) {
+ consumedTop = (consumingStatusBar || consumingCaptionBar) ? mLastTopInset : 0;
+ } else {
+ consumedTop = consumingStatusBar ? mLastTopInset : 0;
+ }
int consumedRight = consumingNavBar ? mLastRightInset : 0;
int consumedBottom = consumingNavBar ? mLastBottomInset : 0;
int consumedLeft = consumingNavBar ? mLastLeftInset : 0;
diff --git a/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java b/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java
index 07be7006cd73..652cba7ed00d 100644
--- a/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java
+++ b/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java
@@ -98,14 +98,15 @@ public class PerfettoProtoLogImpl implements IProtoLog {
this::onTracingFlush,
this::onTracingInstanceStop
);
+ @Nullable
private final ProtoLogViewerConfigReader mViewerConfigReader;
private final ViewerConfigInputStreamProvider mViewerConfigInputStreamProvider;
private final TreeMap<String, IProtoLogGroup> mLogGroups = new TreeMap<>();
private final Runnable mCacheUpdater;
private final int[] mDefaultLogLevelCounts = new int[LogLevel.values().length];
- private final Map<IProtoLogGroup, int[]> mLogLevelCounts = new ArrayMap<>();
- private final Map<IProtoLogGroup, Integer> mCollectStackTraceGroupCounts = new ArrayMap<>();
+ private final Map<String, int[]> mLogLevelCounts = new ArrayMap<>();
+ private final Map<String, Integer> mCollectStackTraceGroupCounts = new ArrayMap<>();
private final Lock mBackgroundServiceLock = new ReentrantLock();
private ExecutorService mBackgroundLoggingService = Executors.newSingleThreadExecutor();
@@ -126,7 +127,7 @@ public class PerfettoProtoLogImpl implements IProtoLog {
}
public PerfettoProtoLogImpl(
- ViewerConfigInputStreamProvider viewerConfigInputStreamProvider,
+ @Nullable ViewerConfigInputStreamProvider viewerConfigInputStreamProvider,
Runnable cacheUpdater
) {
this(viewerConfigInputStreamProvider,
@@ -136,8 +137,8 @@ public class PerfettoProtoLogImpl implements IProtoLog {
@VisibleForTesting
public PerfettoProtoLogImpl(
- ViewerConfigInputStreamProvider viewerConfigInputStreamProvider,
- ProtoLogViewerConfigReader viewerConfigReader,
+ @Nullable ViewerConfigInputStreamProvider viewerConfigInputStreamProvider,
+ @Nullable ProtoLogViewerConfigReader viewerConfigReader,
Runnable cacheUpdater
) {
Producer.init(InitArguments.DEFAULTS);
@@ -168,12 +169,124 @@ public class PerfettoProtoLogImpl implements IProtoLog {
log(logLevel, group, new Message(messageString), args);
}
+ /**
+ * SLog wrapper.
+ */
+ @VisibleForTesting
+ public void passToLogcat(String tag, LogLevel level, String message) {
+ switch (level) {
+ case DEBUG:
+ Slog.d(tag, message);
+ break;
+ case VERBOSE:
+ Slog.v(tag, message);
+ break;
+ case INFO:
+ Slog.i(tag, message);
+ break;
+ case WARN:
+ Slog.w(tag, message);
+ break;
+ case ERROR:
+ Slog.e(tag, message);
+ break;
+ case WTF:
+ Slog.wtf(tag, message);
+ break;
+ }
+ }
+
+ /**
+ * Returns {@code true} iff logging to proto is enabled.
+ */
+ public boolean isProtoEnabled() {
+ return mTracingInstances.get() > 0;
+ }
+
+ /**
+ * Start text logging
+ * @param groups Groups to start text logging for
+ * @param logger A logger to write status updates to
+ * @return status code
+ */
+ public int startLoggingToLogcat(String[] groups, ILogger logger) {
+ if (mViewerConfigReader != null) {
+ mViewerConfigReader.loadViewerConfig(groups, logger);
+ }
+ return setTextLogging(true, logger, groups);
+ }
+
+ /**
+ * Stop text logging
+ * @param groups Groups to start text logging for
+ * @param logger A logger to write status updates to
+ * @return status code
+ */
+ public int stopLoggingToLogcat(String[] groups, ILogger logger) {
+ if (mViewerConfigReader != null) {
+ mViewerConfigReader.unloadViewerConfig(groups, logger);
+ }
+ return setTextLogging(false, logger, groups);
+ }
+
+ @Override
+ public boolean isEnabled(IProtoLogGroup group, LogLevel level) {
+ final int[] groupLevelCount = mLogLevelCounts.get(group.name());
+ return (groupLevelCount == null && mDefaultLogLevelCounts[level.ordinal()] > 0)
+ || (groupLevelCount != null && groupLevelCount[level.ordinal()] > 0)
+ || group.isLogToLogcat();
+ }
+
+ @Override
+ public void registerGroups(IProtoLogGroup... protoLogGroups) {
+ for (IProtoLogGroup protoLogGroup : protoLogGroups) {
+ mLogGroups.put(protoLogGroup.name(), protoLogGroup);
+ }
+ }
+
+ /**
+ * Responds to a shell command.
+ */
+ public int onShellCommand(ShellCommand shell) {
+ PrintWriter pw = shell.getOutPrintWriter();
+ String cmd = shell.getNextArg();
+ if (cmd == null) {
+ return unknownCommand(pw);
+ }
+ ArrayList<String> args = new ArrayList<>();
+ String arg;
+ while ((arg = shell.getNextArg()) != null) {
+ args.add(arg);
+ }
+ final ILogger logger = (msg) -> logAndPrintln(pw, msg);
+ String[] groups = args.toArray(new String[0]);
+ switch (cmd) {
+ case "start", "stop" -> {
+ pw.println("Command not supported. "
+ + "Please start and stop ProtoLog tracing with Perfetto.");
+ return -1;
+ }
+ case "enable-text" -> {
+ if (mViewerConfigReader != null) {
+ mViewerConfigReader.loadViewerConfig(groups, logger);
+ }
+ return setTextLogging(true, logger, groups);
+ }
+ case "disable-text" -> {
+ return setTextLogging(false, logger, groups);
+ }
+ default -> {
+ return unknownCommand(pw);
+ }
+ }
+ }
+
private void log(LogLevel logLevel, IProtoLogGroup group, Message message,
@Nullable Object[] args) {
if (isProtoEnabled()) {
long tsNanos = SystemClock.elapsedRealtimeNanos();
final String stacktrace;
- if (mCollectStackTraceGroupCounts.getOrDefault(group, 0) > 0) {
+ if (mCollectStackTraceGroupCounts.getOrDefault(group.name(), 0) > 0) {
stacktrace = collectStackTrace();
} else {
stacktrace = null;
@@ -314,7 +427,12 @@ public class PerfettoProtoLogImpl implements IProtoLog {
private void logToLogcat(String tag, LogLevel level, Message message,
@Nullable Object[] args) {
- String messageString = message.getMessage(mViewerConfigReader);
+ String messageString;
+ if (mViewerConfigReader == null) {
+ messageString = message.getMessage();
+ } else {
+ messageString = message.getMessage(mViewerConfigReader);
+ }
if (messageString == null) {
StringBuilder builder = new StringBuilder("UNKNOWN MESSAGE");
@@ -346,7 +464,7 @@ public class PerfettoProtoLogImpl implements IProtoLog {
} catch (IllegalArgumentException e) {
message = "FORMAT_ERROR \"" + messageString + "\", args=("
+ String.join(
- ", ", Arrays.stream(args).map(Object::toString).toList()) + ")";
+ ", ", Arrays.stream(args).map(Object::toString).toList()) + ")";
}
} else {
message = messageString;
@@ -354,33 +472,6 @@ public class PerfettoProtoLogImpl implements IProtoLog {
passToLogcat(tag, level, message);
}
- /**
- * SLog wrapper.
- */
- @VisibleForTesting
- public void passToLogcat(String tag, LogLevel level, String message) {
- switch (level) {
- case DEBUG:
- Slog.d(tag, message);
- break;
- case VERBOSE:
- Slog.v(tag, message);
- break;
- case INFO:
- Slog.i(tag, message);
- break;
- case WARN:
- Slog.w(tag, message);
- break;
- case ERROR:
- Slog.e(tag, message);
- break;
- case WTF:
- Slog.wtf(tag, message);
- break;
- }
- }
-
private void logToProto(LogLevel level, IProtoLogGroup logGroup, Message message, Object[] args,
long tsNanos, @Nullable String stacktrace) {
mDataSource.trace(ctx -> {
@@ -627,66 +718,6 @@ public class PerfettoProtoLogImpl implements IProtoLog {
return internMap.get(string);
}
- /**
- * Returns {@code true} iff logging to proto is enabled.
- */
- public boolean isProtoEnabled() {
- return mTracingInstances.get() > 0;
- }
-
- /**
- * Start text logging
- * @param groups Groups to start text logging for
- * @param logger A logger to write status updates to
- * @return status code
- */
- public int startLoggingToLogcat(String[] groups, ILogger logger) {
- mViewerConfigReader.loadViewerConfig(logger);
- return setTextLogging(true, logger, groups);
- }
-
- /**
- * Stop text logging
- * @param groups Groups to start text logging for
- * @param logger A logger to write status updates to
- * @return status code
- */
- public int stopLoggingToLogcat(String[] groups, ILogger logger) {
- mViewerConfigReader.unloadViewerConfig();
- return setTextLogging(false, logger, groups);
- }
-
- @Override
- public boolean isEnabled(IProtoLogGroup group, LogLevel level) {
- final int[] groupLevelCount = mLogLevelCounts.get(group);
- return (groupLevelCount == null && mDefaultLogLevelCounts[level.ordinal()] > 0)
- || (groupLevelCount != null && groupLevelCount[level.ordinal()] > 0)
- || group.isLogToLogcat();
- }
-
- @Override
- public void registerGroups(IProtoLogGroup... protoLogGroups) {
- for (IProtoLogGroup protoLogGroup : protoLogGroups) {
- mLogGroups.put(protoLogGroup.name(), protoLogGroup);
- }
- }
-
- /**
- * Start logging the stack trace of the when the log message happened for target groups
- * @return status code
- */
- public int startLoggingStackTrace(String[] groups, ILogger logger) {
- return -1;
- }
-
- /**
- * Stop logging the stack trace of the when the log message happened for target groups
- * @return status code
- */
- public int stopLoggingStackTrace() {
- return -1;
- }
-
private int setTextLogging(boolean value, ILogger logger, String... groups) {
for (int i = 0; i < groups.length; i++) {
String group = groups[i];
@@ -703,41 +734,6 @@ public class PerfettoProtoLogImpl implements IProtoLog {
return 0;
}
- /**
- * Responds to a shell command.
- */
- public int onShellCommand(ShellCommand shell) {
- PrintWriter pw = shell.getOutPrintWriter();
- String cmd = shell.getNextArg();
- if (cmd == null) {
- return unknownCommand(pw);
- }
- ArrayList<String> args = new ArrayList<>();
- String arg;
- while ((arg = shell.getNextArg()) != null) {
- args.add(arg);
- }
- final ILogger logger = (msg) -> logAndPrintln(pw, msg);
- String[] groups = args.toArray(new String[0]);
- switch (cmd) {
- case "start", "stop" -> {
- pw.println("Command not supported. "
- + "Please start and stop ProtoLog tracing with Perfetto.");
- return -1;
- }
- case "enable-text" -> {
- mViewerConfigReader.loadViewerConfig(logger);
- return setTextLogging(true, logger, groups);
- }
- case "disable-text" -> {
- return setTextLogging(false, logger, groups);
- }
- default -> {
- return unknownCommand(pw);
- }
- }
- }
-
private int unknownCommand(PrintWriter pw) {
pw.println("Unknown command");
pw.println("Window manager logging options:");
@@ -755,15 +751,8 @@ public class PerfettoProtoLogImpl implements IProtoLog {
final Set<String> overriddenGroupTags = config.getGroupTagsWithOverriddenConfigs();
for (String overriddenGroupTag : overriddenGroupTags) {
- IProtoLogGroup group = mLogGroups.get(overriddenGroupTag);
-
- if (group == null) {
- throw new IllegalArgumentException("Trying to set config for \""
- + overriddenGroupTag + "\" that isn't registered");
- }
-
- mLogLevelCounts.putIfAbsent(group, new int[LogLevel.values().length]);
- final int[] logLevelsCountsForGroup = mLogLevelCounts.get(group);
+ mLogLevelCounts.putIfAbsent(overriddenGroupTag, new int[LogLevel.values().length]);
+ final int[] logLevelsCountsForGroup = mLogLevelCounts.get(overriddenGroupTag);
final LogLevel logFromLevel = config.getConfigFor(overriddenGroupTag).logFrom;
for (int i = logFromLevel.ordinal(); i < LogLevel.values().length; i++) {
@@ -771,13 +760,13 @@ public class PerfettoProtoLogImpl implements IProtoLog {
}
if (config.getConfigFor(overriddenGroupTag).collectStackTrace) {
- mCollectStackTraceGroupCounts.put(group,
- mCollectStackTraceGroupCounts.getOrDefault(group, 0) + 1);
+ mCollectStackTraceGroupCounts.put(overriddenGroupTag,
+ mCollectStackTraceGroupCounts.getOrDefault(overriddenGroupTag, 0) + 1);
}
if (config.getConfigFor(overriddenGroupTag).collectStackTrace) {
- mCollectStackTraceGroupCounts.put(group,
- mCollectStackTraceGroupCounts.getOrDefault(group, 0) + 1);
+ mCollectStackTraceGroupCounts.put(overriddenGroupTag,
+ mCollectStackTraceGroupCounts.getOrDefault(overriddenGroupTag, 0) + 1);
}
}
@@ -797,24 +786,22 @@ public class PerfettoProtoLogImpl implements IProtoLog {
final Set<String> overriddenGroupTags = config.getGroupTagsWithOverriddenConfigs();
for (String overriddenGroupTag : overriddenGroupTags) {
- IProtoLogGroup group = mLogGroups.get(overriddenGroupTag);
-
- final int[] logLevelsCountsForGroup = mLogLevelCounts.get(group);
+ final int[] logLevelsCountsForGroup = mLogLevelCounts.get(overriddenGroupTag);
final LogLevel logFromLevel = config.getConfigFor(overriddenGroupTag).logFrom;
- for (int i = defaultLogFrom.ordinal(); i < LogLevel.values().length; i++) {
+ for (int i = logFromLevel.ordinal(); i < LogLevel.values().length; i++) {
logLevelsCountsForGroup[i]--;
}
if (Arrays.stream(logLevelsCountsForGroup).allMatch(it -> it == 0)) {
- mLogLevelCounts.remove(group);
+ mLogLevelCounts.remove(overriddenGroupTag);
}
if (config.getConfigFor(overriddenGroupTag).collectStackTrace) {
- mCollectStackTraceGroupCounts.put(group,
- mCollectStackTraceGroupCounts.get(group) - 1);
+ mCollectStackTraceGroupCounts.put(overriddenGroupTag,
+ mCollectStackTraceGroupCounts.get(overriddenGroupTag) - 1);
- if (mCollectStackTraceGroupCounts.get(group) == 0) {
- mCollectStackTraceGroupCounts.remove(group);
+ if (mCollectStackTraceGroupCounts.get(overriddenGroupTag) == 0) {
+ mCollectStackTraceGroupCounts.remove(overriddenGroupTag);
}
}
}
@@ -822,7 +809,7 @@ public class PerfettoProtoLogImpl implements IProtoLog {
mCacheUpdater.run();
}
- static void logAndPrintln(@Nullable PrintWriter pw, String msg) {
+ private static void logAndPrintln(@Nullable PrintWriter pw, String msg) {
Slog.i(LOG_TAG, msg);
if (pw != null) {
pw.println(msg);
@@ -852,7 +839,11 @@ public class PerfettoProtoLogImpl implements IProtoLog {
return mMessageMask;
}
- private String getMessage(ProtoLogViewerConfigReader viewerConfigReader) {
+ private String getMessage() {
+ return mMessageString;
+ }
+
+ private String getMessage(@NonNull ProtoLogViewerConfigReader viewerConfigReader) {
if (mMessageString != null) {
return mMessageString;
}
diff --git a/core/java/com/android/internal/protolog/ProtoLogViewerConfigReader.java b/core/java/com/android/internal/protolog/ProtoLogViewerConfigReader.java
index b7b24241c26a..bb6c8b7a9698 100644
--- a/core/java/com/android/internal/protolog/ProtoLogViewerConfigReader.java
+++ b/core/java/com/android/internal/protolog/ProtoLogViewerConfigReader.java
@@ -1,20 +1,32 @@
package com.android.internal.protolog;
+import static android.internal.perfetto.protos.Protolog.ProtoLogViewerConfig.GROUPS;
+import static android.internal.perfetto.protos.Protolog.ProtoLogViewerConfig.Group.ID;
+import static android.internal.perfetto.protos.Protolog.ProtoLogViewerConfig.Group.NAME;
+
import static android.internal.perfetto.protos.Protolog.ProtoLogViewerConfig.MESSAGES;
import static android.internal.perfetto.protos.Protolog.ProtoLogViewerConfig.MessageData.MESSAGE;
import static android.internal.perfetto.protos.Protolog.ProtoLogViewerConfig.MessageData.MESSAGE_ID;
+import static android.internal.perfetto.protos.Protolog.ProtoLogViewerConfig.MessageData.GROUP_ID;
-import android.util.ArrayMap;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.util.Log;
+import android.util.LongSparseArray;
import android.util.proto.ProtoInputStream;
import com.android.internal.protolog.common.ILogger;
import java.io.IOException;
import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.TreeMap;
public class ProtoLogViewerConfigReader {
private final ViewerConfigInputStreamProvider mViewerConfigInputStreamProvider;
- private Map<Long, String> mLogMessageMap = null;
+ private final Map<String, Set<Long>> mGroupHashes = new TreeMap<>();
+ private final LongSparseArray<String> mLogMessageMap = new LongSparseArray<>();
public ProtoLogViewerConfigReader(
ViewerConfigInputStreamProvider viewerConfigInputStreamProvider) {
@@ -26,39 +38,62 @@ public class ProtoLogViewerConfigReader {
* or the viewer config is not loaded into memory.
*/
public synchronized String getViewerString(long messageHash) {
- if (mLogMessageMap != null) {
- return mLogMessageMap.get(messageHash);
- } else {
- return null;
- }
+ return mLogMessageMap.get(messageHash);
+ }
+
+ public synchronized void loadViewerConfig(String[] groups) {
+ loadViewerConfig(groups, (message) -> {});
}
/**
* Loads the viewer config into memory. No-op if already loaded in memory.
*/
- public synchronized void loadViewerConfig(ILogger logger) {
- if (mLogMessageMap != null) {
- return;
- }
+ public synchronized void loadViewerConfig(String[] groups, @NonNull ILogger logger) {
+ for (String group : groups) {
+ if (mGroupHashes.containsKey(group)) {
+ continue;
+ }
+
+ try {
+ Map<Long, String> mappings = loadViewerConfigMappingForGroup(group);
+ mGroupHashes.put(group, mappings.keySet());
+ for (Long key : mappings.keySet()) {
+ mLogMessageMap.put(key, mappings.get(key));
+ }
- try {
- doLoadViewerConfig();
- logger.log("Loaded " + mLogMessageMap.size() + " log definitions");
- } catch (IOException e) {
- logger.log("Unable to load log definitions: "
- + "IOException while processing viewer config" + e);
+ logger.log("Loaded " + mLogMessageMap.size() + " log definitions");
+ } catch (IOException e) {
+ logger.log("Unable to load log definitions: "
+ + "IOException while processing viewer config" + e);
+ }
}
}
+ public synchronized void unloadViewerConfig(String[] groups) {
+ unloadViewerConfig(groups, (message) -> {});
+ }
+
/**
* Unload the viewer config from memory.
*/
- public synchronized void unloadViewerConfig() {
- mLogMessageMap = null;
+ public synchronized void unloadViewerConfig(String[] groups, @NonNull ILogger logger) {
+ for (String group : groups) {
+ if (!mGroupHashes.containsKey(group)) {
+ continue;
+ }
+
+ final Set<Long> hashes = mGroupHashes.get(group);
+ for (Long hash : hashes) {
+ logger.log("Unloading viewer config hash " + hash);
+ mLogMessageMap.remove(hash);
+ }
+ }
}
- private void doLoadViewerConfig() throws IOException {
- mLogMessageMap = new ArrayMap<>();
+ private Map<Long, String> loadViewerConfigMappingForGroup(String group) throws IOException {
+ Long targetGroupId = loadGroupId(group);
+
+ final Map<Long, String> hashesForGroup = new TreeMap<>();
final ProtoInputStream pis = mViewerConfigInputStreamProvider.getInputStream();
while (pis.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
@@ -67,6 +102,7 @@ public class ProtoLogViewerConfigReader {
long messageId = 0;
String message = null;
+ int groupId = 0;
while (pis.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pis.getFieldNumber()) {
case (int) MESSAGE_ID:
@@ -75,9 +111,16 @@ public class ProtoLogViewerConfigReader {
case (int) MESSAGE:
message = pis.readString(MESSAGE);
break;
+ case (int) GROUP_ID:
+ groupId = pis.readInt(GROUP_ID);
+ break;
}
}
+ if (groupId == 0) {
+ throw new IOException("Failed to get group id");
+ }
+
if (messageId == 0) {
throw new IOException("Failed to get message id");
}
@@ -86,10 +129,45 @@ public class ProtoLogViewerConfigReader {
throw new IOException("Failed to get message string");
}
- mLogMessageMap.put(messageId, message);
+ if (groupId == targetGroupId) {
+ hashesForGroup.put(messageId, message);
+ }
+
+ pis.end(inMessageToken);
+ }
+ }
+
+ return hashesForGroup;
+ }
+
+ private Long loadGroupId(String group) throws IOException {
+ final ProtoInputStream pis = mViewerConfigInputStreamProvider.getInputStream();
+
+ while (pis.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+ if (pis.getFieldNumber() == (int) GROUPS) {
+ final long inMessageToken = pis.start(GROUPS);
+
+ long groupId = 0;
+ String groupName = null;
+ while (pis.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+ switch (pis.getFieldNumber()) {
+ case (int) ID:
+ groupId = pis.readInt(ID);
+ break;
+ case (int) NAME:
+ groupName = pis.readString(NAME);
+ break;
+ }
+ }
+
+ if (Objects.equals(groupName, group)) {
+ return groupId;
+ }
pis.end(inMessageToken);
}
}
+
+ throw new RuntimeException("Group " + group + "not found in viewer config");
}
}
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index f4ad487f48ac..19c6f51ff9a7 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -22,6 +22,8 @@ import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
+import static android.security.Flags.reportPrimaryAuthAttempts;
+import static android.security.Flags.shouldTrustManagerListenForPrimaryAuth;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -414,7 +416,9 @@ public class LockPatternUtils {
return;
}
getDevicePolicyManager().reportFailedPasswordAttempt(userId);
- getTrustManager().reportUnlockAttempt(false /* authenticated */, userId);
+ if (!reportPrimaryAuthAttempts() || !shouldTrustManagerListenForPrimaryAuth()) {
+ getTrustManager().reportUnlockAttempt(/* authenticated= */ false, userId);
+ }
}
@UnsupportedAppUsage
@@ -423,7 +427,9 @@ public class LockPatternUtils {
return;
}
getDevicePolicyManager().reportSuccessfulPasswordAttempt(userId);
- getTrustManager().reportUnlockAttempt(true /* authenticated */, userId);
+ if (!reportPrimaryAuthAttempts() || !shouldTrustManagerListenForPrimaryAuth()) {
+ getTrustManager().reportUnlockAttempt(/* authenticated= */ true, userId);
+ }
}
public void reportPasswordLockout(int timeoutMs, int userId) {
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index eaff7608ce3b..c07fd3838837 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -2718,12 +2718,11 @@ static jint android_media_AudioSystem_getMaxChannelCount(JNIEnv *env, jobject th
}
static jint android_media_AudioSystem_getMaxSampleRate(JNIEnv *env, jobject thiz) {
- // see frameworks/av/services/audiopolicy/common/include/policy.h
- return 192000; // SAMPLE_RATE_HZ_MAX (for API)
+ return SAMPLE_RATE_HZ_MAX;
}
static jint android_media_AudioSystem_getMinSampleRate(JNIEnv *env, jobject thiz) {
- return 4000; // SAMPLE_RATE_HZ_MIN (for API)
+ return SAMPLE_RATE_HZ_MIN;
}
static std::vector<uid_t> convertJIntArrayToUidVector(JNIEnv *env, jintArray jArray) {
diff --git a/core/proto/android/server/inputmethod/inputmethodmanagerservice.proto b/core/proto/android/server/inputmethod/inputmethodmanagerservice.proto
index b75d545b1305..eddf1d276e4b 100644
--- a/core/proto/android/server/inputmethod/inputmethodmanagerservice.proto
+++ b/core/proto/android/server/inputmethod/inputmethodmanagerservice.proto
@@ -47,4 +47,5 @@ message InputMethodManagerServiceProto {
optional int32 ime_window_visibility = 22;
optional bool show_ime_with_hard_keyboard = 23;
optional bool accessibility_requesting_no_soft_keyboard = 24;
-} \ No newline at end of file
+ optional bool concurrent_multi_user_mode_enabled = 25;
+}
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 336eb31a3229..8aeffbe32339 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -265,8 +265,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"Foutverslag"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Beëindig sessie"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Skermskoot"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"Foutverslag"</string>
<string name="bugreport_message" msgid="5212529146119624326">"Dit sal inligting oor die huidige toestand van jou toestel insamel om as \'n e-posboodskap te stuur. Dit sal \'n tydjie neem vandat die foutverslag begin is totdat dit reg is om gestuur te word; wees asseblief geduldig."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"Interaktiewe verslag"</string>
@@ -1767,12 +1765,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"Die kenmerk sal oopmaak wanneer jy weer op die toeganklikheidknoppie tik"</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"Die kenmerk sal oopmaak wanneer jy weer hierdie kortpad gebruik. Swiep vanaf die onderkant van jou skerm met 2 vingers op en los vinnig."</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"Die kenmerk sal oopmaak wanneer jy weer hierdie kortpad gebruik. Swiep vanaf die onderkant van jou skerm met 3 vingers op en los vinnig."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Vergroting"</string>
<string name="user_switched" msgid="7249833311585228097">"Huidige gebruiker <xliff:g id="NAME">%1$s</xliff:g> ."</string>
<string name="user_switching_message" msgid="1912993630661332336">"Skakel tans oor na <xliff:g id="NAME">%1$s</xliff:g> …"</string>
@@ -2436,17 +2431,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Hoe dit werk"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Hangend …"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Stel Vingerafdrukslot weer op"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> kan nie meer herken word nie."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> en <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> kan nie meer herken word nie."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"<xliff:g id="FINGERPRINT">%s</xliff:g> kan nie meer herken word nie. Stel Vingerafdrukslot weer op."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> en <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> kan nie meer herken word nie. Stel Vingerafdrukslot weer op."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"Stel Gesigslot weer op"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"Jou gesigmodel kan nie meer herken word nie. Stel Gesigslot weer op."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Stel op"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Nie nou nie"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"Alarm vir <xliff:g id="USER_NAME">%s</xliff:g>"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index ad8874fef437..5edfe13a9907 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -265,8 +265,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"የሳንካ ሪፖርት"</string>
<string name="global_action_logout" msgid="6093581310002476511">"ክፍለ-ጊዜን አብቃ"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"ቅጽበታዊ ገፅ ዕይታ"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"የሳንካ ሪፖርት"</string>
<string name="bugreport_message" msgid="5212529146119624326">"ይሄ እንደ የኢሜይል መልዕክት አድርጎ የሚልከውን ስለመሣሪያዎ የአሁኑ ሁኔታ መረጃ ይሰበስባል። የሳንካ ሪፖርቱን ከመጀመር ጀምሮ እስኪላክ ድረስ ትንሽ ጊዜ ይወስዳል፤ እባክዎ ይታገሱ።"</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"መስተጋብራዊ ሪፖርት"</string>
@@ -1767,12 +1765,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"በቀጣይ ጊዜ የተደራሽነት አዝራሩን መታ ሲያደርጉ ባህሪው ይከፈታል"</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"በቀጣይ ጊዜ ይህን አቋራጭ ሲመለከቱ ባህሪው ይከፈታል። ከማያ ገፅዎ ታች በ2 ጣቶች ወደላይ ያንሸራትቱ እና በፍጥነት ይልቀቁ።"</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"በቀጣይ ጊዜ ይህን አቋራጭ ሲመለከቱ ባህሪው ይከፈታል። ከማያ ገፅዎ ታች ወደላይ በ3 ጣቶች ያንሸራትቱ እና ወዲያው ይልቀቁ።"</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"ማጉላት"</string>
<string name="user_switched" msgid="7249833311585228097">"የአሁኑ ተጠቃሚ <xliff:g id="NAME">%1$s</xliff:g>።"</string>
<string name="user_switching_message" msgid="1912993630661332336">"ወደ <xliff:g id="NAME">%1$s</xliff:g> በመቀየር ላይ…"</string>
@@ -2436,17 +2431,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"እንዴት እንደሚሠራ"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"በመጠባበቅ ላይ..."</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"በጣት አሻራ መክፈቻን እንደገና ያዋቅሩ"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> ከእንግዲህ መለየት አይችልም።"</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> እና <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> ከእንግዲህ መለየት አይችሉም።"</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"<xliff:g id="FINGERPRINT">%s</xliff:g> ከእንግዲህ መለየት አይችልም። በጣት አሻራ መክፈቻን እንደገና ያዋቅሩ።"</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> እና <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> ከእንግዲህ መለየት አይችሉም። በጣት አሻራ መክፈቻን እንደገና ያዋቅሩ።"</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"በመልክ መክፈትን እንደገና ያዋቅሩ"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"የመልክ ሞዴልዎ ከእንግዲህ መለየት አይችልም። በመልክ መክፈትን እንደገና ያዋቅሩ።"</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"ያዋቅሩ"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"አሁን አይደለም"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"ለ<xliff:g id="USER_NAME">%s</xliff:g> ማንቂያ"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index ee90210d7b3c..e0d194922e8f 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -269,8 +269,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"تقرير الأخطاء"</string>
<string name="global_action_logout" msgid="6093581310002476511">"إنهاء الجلسة"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"لقطة شاشة"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"تقرير الأخطاء"</string>
<string name="bugreport_message" msgid="5212529146119624326">"سيجمع هذا معلومات حول حالة جهازك الحالي لإرسالها كرسالة إلكترونية، ولكنه سيستغرق وقتًا قليلاً من بدء عرض تقرير بالأخطاء. وحتى يكون جاهزًا للإرسال، يُرجى الانتظار."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"تقرير تفاعلي"</string>
@@ -1779,7 +1777,7 @@
<string name="user_switching_message" msgid="1912993630661332336">"جارٍ التبديل إلى <xliff:g id="NAME">%1$s</xliff:g>…"</string>
<string name="user_logging_out_message" msgid="7216437629179710359">"جارٍ الخروج <xliff:g id="NAME">%1$s</xliff:g>…"</string>
<string name="owner_name" msgid="8713560351570795743">"المالك"</string>
- <string name="guest_name" msgid="8502103277839834324">"ضيف"</string>
+ <string name="guest_name" msgid="8502103277839834324">"وضع الضيف"</string>
<string name="error_message_title" msgid="4082495589294631966">"خطأ"</string>
<string name="error_message_change_not_allowed" msgid="843159705042381454">"لا يسمح المشرف بإجراء هذا التغيير"</string>
<string name="app_not_found" msgid="3429506115332341800">"لم يتم العثور على تطبيق يمكنه التعامل مع هذا الإجراء."</string>
@@ -2437,17 +2435,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"طريقة العمل"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"بانتظار الإزالة من الأرشيف…"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"إعادة إعداد ميزة \"فتح الجهاز ببصمة الإصبع\""</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"لا يمكن بعد الآن التعرّف على \"<xliff:g id="FINGERPRINT">%s</xliff:g>\"."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"لا يمكن بعد الآن التعرّف على \"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g>\" و\"<xliff:g id="FINGERPRINT_1">%2$s</xliff:g>\"."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"لا يمكن بعد الآن التعرّف على \"<xliff:g id="FINGERPRINT">%s</xliff:g>\". يجب ضبط ميزة \"فتح الجهاز ببصمة الإصبع\" مجددًا."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"لا يمكن بعد الآن التعرّف على \"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g>\" و\"<xliff:g id="FINGERPRINT_1">%2$s</xliff:g>\". يجب ضبط ميزة \"فتح الجهاز ببصمة الإصبع\" مجددًا."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"إعادة إعداد ميزة \"فتح الجهاز بالتعرّف على الوجه\""</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"لا يمكن بعد الآن التعرّف على نموذج الوجه الخاص بك. يجب ضبط ميزة \"فتح الجهاز بالتعرّف على الوجه\" مجددًا."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"إعداد"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"لاحقًا"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"تنبيه لـ \"<xliff:g id="USER_NAME">%s</xliff:g>\""</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index 599d46977f60..b9a71b37900d 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -265,8 +265,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"বাগ সম্পর্কীয় অভিযোগ"</string>
<string name="global_action_logout" msgid="6093581310002476511">"ছেশ্বন সমাপ্ত কৰক"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"স্ক্ৰীনশ্বট"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"বাগ সম্পর্কীয় অভিযোগ"</string>
<string name="bugreport_message" msgid="5212529146119624326">"এই কার্যই ইমেইল বাৰ্তা হিচাপে পঠিয়াবলৈ আপোনাৰ ডিভাইচৰ বৰ্তমান অৱস্থাৰ বিষয়ে তথ্য সংগ্ৰহ কৰিব৷ ইয়াক বাগ সম্পর্কীয় অভিযোগ পঠিওৱা কাৰ্য আৰম্ভ কৰোঁতে অলপ সময় লাগিব; অনুগ্ৰহ কৰি ধৈৰ্য ধৰক।"</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"ইণ্টাৰেক্টিভ অভিযোগ"</string>
@@ -2433,17 +2431,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"ই কেনেকৈ কাম কৰে"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"বিবেচনাধীন হৈ আছে..."</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"ফিংগাৰপ্ৰিণ্ট আনলক পুনৰ ছেট আপ কৰক"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> আৰু চিনাক্ত কৰিব নোৱাৰি।"</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> আৰু <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> আৰু চিনাক্ত কৰিব নোৱাৰি।"</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"<xliff:g id="FINGERPRINT">%s</xliff:g> আৰু চিনাক্ত কৰিব নোৱাৰি। ফিংগাৰপ্ৰিণ্ট আনলক পুনৰ ছেট আপ কৰক।"</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> আৰু <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> আৰু চিনাক্ত কৰিব নোৱাৰি। ফিংগাৰপ্ৰিণ্ট আনলক পুনৰ ছেট আপ কৰক।"</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"ফে’চ আনলক পুনৰ ছেট আপ কৰক"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"আপোনাৰ মুখাৱয়বৰ মডেলটো আৰু চিনাক্ত কৰিব নোৱাৰি। ফে’চ আনলক পুনৰ ছেট আপ কৰক।"</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"ছেট আপ কৰক"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"এতিয়া নহয়"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"<xliff:g id="USER_NAME">%s</xliff:g>ৰ বাবে এলাৰ্ম"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index a22cf4ac7b2d..764780f3a4da 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -265,8 +265,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"Baq hesabatı"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Sessiyanı sonlandırın"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Skrinşot"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"Baq hesabatı"</string>
<string name="bugreport_message" msgid="5212529146119624326">"Bu, sizin hazırkı cihaz durumu haqqında məlumat toplayacaq ki, elektron məktub şəklində göndərsin. Baq raportuna başlamaq üçün bir az vaxt lazım ola bilər, bir az səbr edin."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"İnteraktiv hesabat"</string>
@@ -1767,12 +1765,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"Növbəti dəfə xüsusi imkanlar düyməsinə toxunduğunuz zaman funksiya açılacaq"</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"Növbəti dəfə bu qısayoldan istifadə etdiyiniz zaman funksiya açılacaq. Ekranın aşağısından 2 barmaq ilə yuxarı çəkin və tez buraxın."</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"Növbəti dəfə bu qısayoldan istifadə etdiyiniz zaman funksiya açılacaq. Ekranın aşağısından 3 barmaq ilə yuxarı çəkin və tez buraxın."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Böyütmə"</string>
<string name="user_switched" msgid="7249833311585228097">"Cari istifadəçi <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="1912993630661332336">"<xliff:g id="NAME">%1$s</xliff:g> adına keçirilir…"</string>
@@ -2436,17 +2431,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Haqqında"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Gözləmədə..."</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Barmaqla Kilidaçmanı yenidən ayarlayın"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> artıq tanınmır."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> və <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> artıq tanınmır."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"<xliff:g id="FINGERPRINT">%s</xliff:g> artıq tanınmır. Barmaqla Kilidaçmanı yenidən ayarlayın."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> və <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> artıq tanınmır. Barmaqla Kilidaçmanı yenidən ayarlayın."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"Üzlə Kilidaçmanı yenidən ayarlayın"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"Üz modeliniz artıq tanınmır. Üzlə Kilidaçmanı yenidən ayarlayın."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Ayarlayın"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"İndi yox"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"<xliff:g id="USER_NAME">%s</xliff:g> üçün alarm"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 8da8c2ffb000..aad68d3a5ea8 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -266,8 +266,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"Javi grešku"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Završi sesiju"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Snimak ekrana"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"Javi grešku"</string>
<string name="bugreport_message" msgid="5212529146119624326">"Ovim će se prikupiti informacije o trenutnom stanju uređaja kako bi bile poslate u poruci e-pošte. Od započinjanja izveštaja o grešci do trenutka za njegovo slanje proći će neko vreme; budite strpljivi."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"Interaktiv. izveštaj"</string>
@@ -1768,12 +1766,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"Funkcija će se otvoriti kada sledeći put dodirnete dugme Pristupačnost"</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"Funkcija će se otvoriti kada sledeći put budete koristili ovu prečicu. Prevucite nagore od dna ekrana sa 2 prsta i brzo pustite."</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"Funkcija će se otvoriti kada sledeći put budete koristili ovu prečicu. Prevucite nagore od dna ekrana sa 3 prsta i brzo pustite."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Uvećanje"</string>
<string name="user_switched" msgid="7249833311585228097">"Aktuelni korisnik <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="1912993630661332336">"Prebacivanje na <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2437,17 +2432,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Princip rada"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Na čekanju..."</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Ponovo podesite otključavanje otiskom prsta"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> više ne može da se prepozna."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> i <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> više ne mogu da se prepoznaju."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"<xliff:g id="FINGERPRINT">%s</xliff:g> više ne može da se prepozna. Ponovo podesite otključavanje otiskom prsta."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> i <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> više ne mogu da se prepoznaju. Ponovo podesite otključavanje otiskom prsta."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"Ponovo podesite otključavanje licem"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"Vaš model lica više ne može da se prepozna. Ponovo podesite otključavanje licem."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Podesi"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Ne sada"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"Alarm za: <xliff:g id="USER_NAME">%s</xliff:g>"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 28f9ebc57e48..993457fcf01d 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -267,8 +267,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"Справаздача пра памылкі"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Скончыць сеанс"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Здымак экрана"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"Справаздача"</string>
<string name="bugreport_message" msgid="5212529146119624326">"Будзе збiрацца iнфармацыя пра бягучы стан прылады, якая будзе адпраўляцца на электронную пошту. Стварэнне справаздачы пра памылкi зойме некаторы час."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"Інтэрактыўная справаздача"</string>
@@ -2435,17 +2433,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Як гэта працуе"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"У чаканні..."</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Наладзіць разблакіроўку адбіткам пальца паўторна"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"Адбітак пальца \"<xliff:g id="FINGERPRINT">%s</xliff:g>\" больш не можа быць распазнаны."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"Адбіткі пальцаў \"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g>\" і \"<xliff:g id="FINGERPRINT_1">%2$s</xliff:g>\" больш не могуць быць распазнаны."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"Адбітак пальца \"<xliff:g id="FINGERPRINT">%s</xliff:g>\" больш не можа быць распазнаны. Паўторна наладзьце разблакіроўку адбіткам пальца."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"Адбіткі пальцаў \"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g>\" і \"<xliff:g id="FINGERPRINT_1">%2$s</xliff:g>\" больш не могуць быць распазнаны. Паўторна наладзьце разблакіроўку адбіткам пальца."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"Паўторна наладзьце распазнаванне твару"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"Мадэль твару больш не можа быць распазнана. Паўторна наладзьце распазнаванне твару."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Наладзіць"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Не зараз"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"Будзільнік карыстальніка <xliff:g id="USER_NAME">%s</xliff:g>"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index b9934777c82f..336002574d29 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -265,8 +265,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"Сигнал за грешка"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Прекратяване на сесията"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Екранна снимка"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"Сигнал за грешка"</string>
<string name="bugreport_message" msgid="5212529146119624326">"По този начин ще се събере информация за текущото състояние на устройството ви, която да се изпрати като имейл съобщение. След стартирането на процеса ще мине известно време, докато сигналът за програмна грешка бъде готов за подаване. Моля, имайте търпение."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"Интерактивен сигнал"</string>
@@ -1767,12 +1765,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"Функцията ще се отвори при следващото докосване бутона за достъпност"</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"Функцията ще се отвори при следващото използване на този пряк път. Прекарайте 2 пръста нагоре от долната част на екрана и бързо освободете."</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"Функцията ще се отвори при следващото използване на този пряк път. Прекарайте 3 пръста нагоре от долната част на екрана и бързо освободете."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Увеличение"</string>
<string name="user_switched" msgid="7249833311585228097">"Текущ потребител <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="1912993630661332336">"Превключва се към: <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2436,17 +2431,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Начин на работа"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Изчаква..."</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Повторно настройване на „Отключване с отпечатък“"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> вече не може да се разпознае."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> и <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> вече не могат да бъдат разпознати."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"<xliff:g id="FINGERPRINT">%s</xliff:g> вече не може да се разпознае. Настройте отново „Отключване с отпечатък“."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> и <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> вече не могат да бъдат разпознати. Настройте отново „Отключване с отпечатък“."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"Повторно настройване на „Отключване с лице“"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"Моделът на лицето ви вече не може да бъде разпознат. Настройте отново „Отключване с лице“."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Настройване"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Не сега"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"Будилник за <xliff:g id="USER_NAME">%s</xliff:g>"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index ca5c47110b4b..1a7fc6bf4287 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -265,8 +265,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"ত্রুটির প্রতিবেদন"</string>
<string name="global_action_logout" msgid="6093581310002476511">"সেশন শেষ করুন"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"স্ক্রিনশট নিন"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"সমস্যার রিপোর্ট"</string>
<string name="bugreport_message" msgid="5212529146119624326">"এটি একটি ই-মেল মেসেজ পাঠানোর জন্য আপনার ডিভাইসের বর্তমান অবস্থা সম্পর্কে তথ্য সংগ্রহ করবে৷ ত্রুটির প্রতিবেদন শুরুর সময় থেকে এটি পাঠানোর জন্য প্রস্তুত হতে কিছুটা সময় নেবে; অনুগ্রহ করে ধৈর্য রাখুন৷"</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"ইন্টারেক্টিভ প্রতিবেদন"</string>
@@ -1767,12 +1765,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"পরের বার অ্যাক্সেসিবিলিটি বোতামে ট্যাপ করলে, ফিচারটি চালু হয়ে যাবে"</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"পরের বার এই শর্টকাট ব্যবহার করলে, ফিচারটি চালু হয়ে যাবে। ২টি আঙ্গুল দিয়ে স্ক্রিনের নিচ থেকে উপরের দিকে সোয়াইপ করে দ্রুত ছেড়ে দিন।"</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"পরের বার এই শর্টকাট ব্যবহার করলে, ফিচারটি চালু হয়ে যাবে। ৩টি আঙ্গুল দিয়ে স্ক্রিনের নিচ থেকে উপরের দিকে সোয়াইপ করে দ্রুত ছেড়ে দিন।"</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"বড় করে দেখা"</string>
<string name="user_switched" msgid="7249833311585228097">"বর্তমান ব্যবহারকারী <xliff:g id="NAME">%1$s</xliff:g>৷"</string>
<string name="user_switching_message" msgid="1912993630661332336">"<xliff:g id="NAME">%1$s</xliff:g> প্রোফাইলে পাল্টানো হচ্ছে…"</string>
@@ -2436,17 +2431,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"এটি কীভাবে কাজ করে"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"বাকি আছে…"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"\'ফিঙ্গারপ্রিন্ট আনলক\' আবার সেট-আপ করুন"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> আর শনাক্ত করা যাবে না।"</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> ও <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> আর শনাক্ত করা যাবে না।"</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"<xliff:g id="FINGERPRINT">%s</xliff:g> আর শনাক্ত করা যাবে না। ফিঙ্গারপ্রিন্ট আনলক আবার সেট-আপ করুন।"</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> ও <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> আর শনাক্ত করা যাবে না। ফিঙ্গারপ্রিন্ট আনলক আবার সেট-আপ করুন।"</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"\'ফেস আনলক\' আবার সেট-আপ করুন"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"আপনার ফেস মডেল আর শনাক্ত করা যাবে না। ফেস আনলক আবার সেট-আপ করুন।"</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"সেট-আপ করুন"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"এখন নয়"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"<xliff:g id="USER_NAME">%s</xliff:g>-এর জন্য অ্যালার্ম"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 4a1aaedc1697..37bb750842f3 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -266,8 +266,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"Izvještaj o greškama"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Završi sesiju"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Snimak ekrana"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"Izvještaj o greškama"</string>
<string name="bugreport_message" msgid="5212529146119624326">"Ovim će se prikupljati informacije o trenutnom stanju uređaja, koji će biti poslani kao e-poruka. Može malo potrajati dok se izvještaj o greškama ne kreira i bude spreman za slanje. Budite strpljivi."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"Interaktivni izvještaj"</string>
@@ -1768,12 +1766,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"Funkcija će se otvoriti sljedeći put kada dodirnete dugme za pristupačnost"</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"Funkcija će se otvoriti sljedeći put kada upotrijebite ovu prečicu. Prevucite s 2 prsta s dna ekrana i brzo pustite."</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"Funkcija će se otvoriti sljedeći put kada upotrijebite ovu prečicu. Prevucite s 3 prsta s dna ekrana i brzo pustite."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Uvećavanje"</string>
<string name="user_switched" msgid="7249833311585228097">"Trenutni korisnik <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="1912993630661332336">"Prebacivanje na korisnika <xliff:g id="NAME">%1$s</xliff:g>..."</string>
@@ -2437,17 +2432,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Kako ovo funkcionira"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Na čekanju…"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Ponovo postavite otključavanje otiskom prsta"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> se više ne može prepoznati."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> i <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> se više ne mogu prepoznati."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"<xliff:g id="FINGERPRINT">%s</xliff:g> se više ne može prepoznati. Ponovo postavite otključavanje otiskom prsta."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> i <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> se više ne mogu prepoznati. Ponovo postavite otključavanje otiskom prsta."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"Ponovo postavite otključavanje licem"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"Vaš model lica se više ne može prepoznati. Ponovo postavite otključavanje licem."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Postavite"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Ne sada"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"Alarm za: <xliff:g id="USER_NAME">%s</xliff:g>"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index a3b13f1a5972..fa10e4568bcd 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -266,8 +266,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"Informe d\'error"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Finalitza la sessió"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Captura de pantalla"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"Informe d\'errors"</string>
<string name="bugreport_message" msgid="5212529146119624326">"Es recopilarà informació sobre l\'estat actual del dispositiu i se t\'enviarà per correu electrònic. Passaran uns quants minuts des de l\'inici de l\'informe d\'errors fins al seu enviament, per la qual cosa et recomanem que tinguis paciència."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"Informe interactiu"</string>
@@ -1768,12 +1766,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"La funció s\'obrirà la pròxima vegada que toquis el botó d\'accessibilitat"</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"La funció s\'obrirà la pròxima vegada que utilitzis aquesta drecera. Llisca cap amunt amb 2 dits des de la part inferior de la pantalla i aixeca\'ls ràpidament."</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"La funció s\'obrirà la pròxima vegada que utilitzis aquesta drecera. Llisca cap amunt amb 3 dits des de la part inferior de la pantalla i aixeca\'ls ràpidament."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Ampliació"</string>
<string name="user_switched" msgid="7249833311585228097">"Usuari actual: <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="1912993630661332336">"S\'està canviant a <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2437,17 +2432,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Com funciona"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Pendent..."</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Torna a configurar Desbloqueig amb empremta digital"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> ja no es pot reconèixer."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> i <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> ja no es poden reconèixer."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"<xliff:g id="FINGERPRINT">%s</xliff:g> ja no es pot reconèixer. Torna a configurar Desbloqueig amb empremta digital."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> i <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> ja no es poden reconèixer. Torna a configurar Desbloqueig amb empremta digital."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"Torna a configurar Desbloqueig facial"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"El teu model facial ja no es pot reconèixer. Torna a configurar Desbloqueig facial."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Configura"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Ara no"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"Alarma per a <xliff:g id="USER_NAME">%s</xliff:g>"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index a5a42c3357ad..a4e5b28371de 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -267,8 +267,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"Hlášení chyb"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Ukončit relaci"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Snímek obrazovky"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"Hlášení chyb"</string>
<string name="bugreport_message" msgid="5212529146119624326">"Shromažďuje informace o aktuálním stavu zařízení. Tyto informace je následně možné poslat v e-mailové zprávě, chvíli však potrvá, než bude hlášení o chybě připraveno k odeslání. Buďte prosím trpěliví."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"Interaktivní přehled"</string>
@@ -1443,7 +1441,7 @@
<string name="fast_scroll_numeric_alphabet" msgid="2529539945421557329">" 0123456789AÁBCČDĎEÉĚFGHCHIÍJKLMNŇOÓPQRŘSŠTŤUÚVWXYÝZŽ"</string>
<string name="alert_windows_notification_channel_group_name" msgid="6063891141815714246">"Zobrazení přes ostatní aplikace"</string>
<string name="alert_windows_notification_channel_name" msgid="3437528564303192620">"Aplikace <xliff:g id="NAME">%s</xliff:g> se zobrazuje přes ostatní aplikace"</string>
- <string name="alert_windows_notification_title" msgid="6331662751095228536">"<xliff:g id="NAME">%s</xliff:g> se zobrazuje přes ostatní aplikace"</string>
+ <string name="alert_windows_notification_title" msgid="6331662751095228536">"Aplikace <xliff:g id="NAME">%s</xliff:g> se zobrazuje přes ostatní aplikace"</string>
<string name="alert_windows_notification_message" msgid="6538171456970725333">"Pokud nechcete, aby aplikace <xliff:g id="NAME">%s</xliff:g> tuto funkci používala, klepnutím otevřete nastavení a funkci vypněte."</string>
<string name="alert_windows_notification_turn_off_action" msgid="7805857234839123780">"Vypnout"</string>
<string name="ext_media_checking_notification_title" msgid="8299199995416510094">"Kontroluje se <xliff:g id="NAME">%s</xliff:g>…"</string>
@@ -1769,12 +1767,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"Funkce se otevře, až příště klepnete na tlačítko přístupnosti"</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"Funkce se otevře při příštím použití této zkratky. Přejeďte dvěma prsty nahoru ze spodní části obrazovky a rychle je zvedněte."</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"Funkce se otevře při příštím použití této zkratky. Přejeďte třemi prsty nahoru ze spodní části obrazovky a rychle je zvedněte."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Zvětšení"</string>
<string name="user_switched" msgid="7249833311585228097">"Aktuální uživatel je <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="1912993630661332336">"Přepínání na uživatele <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2438,17 +2433,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Jak to funguje"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Čeká na vyřízení…"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Opětovné nastavení odemknutí otiskem prstu"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> se nedaří rozpoznat."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> a <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> se nedaří rozpoznat."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"<xliff:g id="FINGERPRINT">%s</xliff:g> se nedaří rozpoznat. Nastavte odemknutí otiskem prstu znovu."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> a <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> se nedaří rozpoznat. Nastavte odemknutí otiskem prstu znovu."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"Nastavte odemknutí obličejem znovu"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"Váš model obličeje se nedaří rozpoznat. Nastavte odemknutí obličejem znovu."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Nastavit"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Teď ne"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"Budík pro uživatele <xliff:g id="USER_NAME">%s</xliff:g>"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 66ab048dab09..4d10a6da54ac 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -265,8 +265,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"Fejlrapport"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Afslut sessionen"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Screenshot"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"Fejlrapport"</string>
<string name="bugreport_message" msgid="5212529146119624326">"Der indsamles oplysninger om din enheds aktuelle status, der efterfølgende sendes i en mail. Der går lidt tid, fra fejlrapporten påbegyndes, til den er klar til at blive sendt. Tak for tålmodigheden."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"Interaktiv rapport"</string>
@@ -1767,12 +1765,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"Funktionen åbnes næste gang, du trykker på knappen til hjælpefunktioner"</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"Funktionen åbnes næste gang, du bruger denne genvej. Stryg opad fra bunden af skærmen med 2 fingre, og slip derefter hurtigt."</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"Funktionen åbnes næste gang, du bruger denne genvej. Stryg opad fra bunden af skærmen med 3 fingre, og slip derefter hurtigt."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Forstørrelse"</string>
<string name="user_switched" msgid="7249833311585228097">"Nuværende bruger <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="1912993630661332336">"Skifter til <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2156,7 +2151,7 @@
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Denne notifikation blev placeret højere. Tryk for at give feedback."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Denne notifikation blev placeret lavere. Tryk for at give feedback."</string>
<string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Forbedrede notifikationer"</string>
- <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Foreslåede handlinger og svar leveres nu via forbedrede notifikationer. Tilpassede Android-notifikationer understøttes ikke længere."</string>
+ <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Foreslåede handlinger og svar leveres nu via forbedrede notifikationer. Adaptive Android-notifikationer understøttes ikke længere."</string>
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Deaktiver"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Få flere oplysninger"</string>
@@ -2436,17 +2431,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Sådan fungerer det"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Afventer…"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Konfigurer fingeroplåsning igen"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> kan ikke længere genkendes."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> og <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> kan ikke længere genkendes."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"<xliff:g id="FINGERPRINT">%s</xliff:g> kan ikke længere genkendes. Konfigurer fingeroplåsning igen."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> og <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> kan ikke længere genkendes. Konfigurer fingeroplåsning igen."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"Konfigurer ansigtsoplåsning igen"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"Din ansigtsmodel kan ikke længere genkendes. Konfigurer ansigtsoplåsning igen."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Konfigurer"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Ikke nu"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"Alarm til <xliff:g id="USER_NAME">%s</xliff:g>"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 162b782f2f03..d22aec8b91f5 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -265,8 +265,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"Fehlerbericht"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Sitzung beenden"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Screenshot"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"Fehlerbericht"</string>
<string name="bugreport_message" msgid="5212529146119624326">"Bei diesem Fehlerbericht werden Daten zum aktuellen Status deines Geräts erfasst und als E-Mail versandt. Vom Start des Berichts bis zu seinem Versand kann es eine Weile dauern. Bitte habe etwas Geduld."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"Interaktiver Bericht"</string>
@@ -347,7 +345,7 @@
<string name="permgroupdesc_phone" msgid="270048070781478204">"Telefonanrufe tätigen und verwalten"</string>
<string name="permgrouplab_sensors" msgid="9134046949784064495">"Körpersensoren"</string>
<string name="permgroupdesc_sensors" msgid="2610631290633747752">"auf Sensordaten zu deinen Vitaldaten zugreifen"</string>
- <string name="permgrouplab_notifications" msgid="5472972361980668884">"Benachrichtigungen"</string>
+ <string name="permgrouplab_notifications" msgid="5472972361980668884">"Benachrichtigun­gen"</string>
<string name="permgroupdesc_notifications" msgid="4608679556801506580">"Benachrichtigungen anzeigen"</string>
<string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Fensterinhalte abrufen"</string>
<string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Die Inhalte eines Fensters, mit dem du interagierst, werden abgerufen."</string>
@@ -1767,12 +1765,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"Die Funktion wird geöffnet, wenn du das nächste Mal auf die Schaltfläche „Bedienungshilfen“ tippst"</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"Die Funktion wird geöffnet, wenn du diese Touch-Geste für Bedienungshilfen das nächste Mal verwendest. Wische mit 2 Fingern vom unteren Displayrand nach oben und lass dann schnell los."</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"Die Funktion wird geöffnet, wenn du diese Touch-Geste für Bedienungshilfen das nächste Mal verwendest. Wische mit 3 Fingern vom unteren Displayrand nach oben und lass dann schnell los."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Vergrößerung"</string>
<string name="user_switched" msgid="7249833311585228097">"Aktueller Nutzer <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="user_switching_message" msgid="1912993630661332336">"Wechseln zu <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2436,17 +2431,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"So funktionierts"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Ausstehend…"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Entsperrung per Fingerabdruck neu einrichten"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> wird nicht mehr erkannt."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> und <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> werden nicht mehr erkannt."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"<xliff:g id="FINGERPRINT">%s</xliff:g> wird nicht mehr erkannt. Richte die Entsperrung per Fingerabdruck neu ein."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> und <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> werden nicht mehr erkannt. Richte die Entsperrung per Fingerabdruck neu ein."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"Entsperrung per Gesichtserkennung neu einrichten"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"Dein Gesichtsmodell wird nicht mehr erkannt. Richte die Entsperrung per Gesichtserkennung neu ein."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Einrichten"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Nicht jetzt"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"Wecker für <xliff:g id="USER_NAME">%s</xliff:g>"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 0e0a58289116..8321d6063ae0 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -265,8 +265,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"Αναφορά σφαλμάτων"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Λήξη περιόδου σύνδεσης"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Στιγμιότυπο οθόνης"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"Αναφορά σφάλματος"</string>
<string name="bugreport_message" msgid="5212529146119624326">"Θα συλλέξει πληροφορίες σχετικά με την τρέχουσα κατάσταση της συσκευής σας και θα τις στείλει μέσω μηνύματος ηλεκτρονικού ταχυδρομείου. Απαιτείται λίγος χρόνος για τη σύνταξη της αναφοράς σφάλματος και την αποστολή της. Κάντε λίγη υπομονή."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"Διαδραστική αναφορά"</string>
@@ -1441,7 +1439,7 @@
<string name="fast_scroll_numeric_alphabet" msgid="2529539945421557329">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="alert_windows_notification_channel_group_name" msgid="6063891141815714246">"Εμφάνιση πάνω σε άλλες εφαρμογές"</string>
<string name="alert_windows_notification_channel_name" msgid="3437528564303192620">"Η εφαρμογή <xliff:g id="NAME">%s</xliff:g> προβάλλεται πάνω από άλλες εφαρμογές"</string>
- <string name="alert_windows_notification_title" msgid="6331662751095228536">"Η εφαρμογή <xliff:g id="NAME">%s</xliff:g> επικαλύπτει άλλες"</string>
+ <string name="alert_windows_notification_title" msgid="6331662751095228536">"Η εφαρ. <xliff:g id="NAME">%s</xliff:g> επικαλύπτει άλλες"</string>
<string name="alert_windows_notification_message" msgid="6538171456970725333">"Εάν δεν θέλετε να χρησιμοποιείται αυτή η λειτουργία από την εφαρμογή <xliff:g id="NAME">%s</xliff:g>, πατήστε για να ανοίξετε τις ρυθμίσεις και απενεργοποιήστε την."</string>
<string name="alert_windows_notification_turn_off_action" msgid="7805857234839123780">"Απενεργοποίηση"</string>
<string name="ext_media_checking_notification_title" msgid="8299199995416510094">"Έλεγχος <xliff:g id="NAME">%s</xliff:g>…"</string>
@@ -1767,12 +1765,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"Η λειτουργία θα ανοίξει την επόμενη φορά που θα πατήσετε το κουμπί προσβασιμότητας"</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"Η λειτουργία θα ανοίξει την επόμενη φορά που θα χρησιμοποιήσετε αυτή τη συντόμευση. Σαρώστε προς τα πάνω με 2 δάχτυλα από το κάτω μέρος της οθόνης και απομακρύνετε γρήγορα τα δάχτυλά σας."</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"Η λειτουργία θα ανοίξει την επόμενη φορά που θα χρησιμοποιήσετε αυτή τη συντόμευση. Σαρώστε προς τα πάνω με 3 δάχτυλα από το κάτω μέρος της οθόνης και απομακρύνετε γρήγορα τα δάχτυλά σας."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Μεγιστοποίηση"</string>
<string name="user_switched" msgid="7249833311585228097">"Τρέχων χρήστης <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="1912993630661332336">"Εναλλαγή σε <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2436,17 +2431,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Πώς λειτουργεί"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Σε εκκρεμότητα…"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Επαναρρύθμιση λειτουργίας Ξεκλείδωμα με δακτυλικό αποτύπωμα"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"Δεν είναι πλέον δυνατή η αναγνώριση του <xliff:g id="FINGERPRINT">%s</xliff:g>."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"Δεν είναι πλέον δυνατή η αναγνώριση του <xliff:g id="FINGERPRINT_0">%1$s</xliff:g> και του <xliff:g id="FINGERPRINT_1">%2$s</xliff:g>."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"Δεν είναι πλέον δυνατή η αναγνώριση του <xliff:g id="FINGERPRINT">%s</xliff:g>. Ρυθμίστε ξανά τη λειτουργία Ξεκλείδωμα με δακτυλικό αποτύπωμα."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"Δεν είναι πλέον δυνατή η αναγνώριση του <xliff:g id="FINGERPRINT_0">%1$s</xliff:g> και του <xliff:g id="FINGERPRINT_1">%2$s</xliff:g>. Ρυθμίστε ξανά τη λειτουργία Ξεκλείδωμα με δακτυλικό αποτύπωμα."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"Επαναρρύθμιση λειτουργίας Ξεκλείδωμα με το πρόσωπο"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"Δεν είναι πλέον δυνατή η αναγνώριση του μοντέλου προσώπου σας. Ρυθμίστε ξανά τη λειτουργία Ξεκλείδωμα με το πρόσωπο."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Ρύθμιση"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Όχι τώρα"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"Ξυπνητήρι για τον χρήστη <xliff:g id="USER_NAME">%s</xliff:g>"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 73081b8ef684..39f55dde0313 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -265,8 +265,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"Bug report"</string>
<string name="global_action_logout" msgid="6093581310002476511">"End session"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Screenshot"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"Bug report"</string>
<string name="bugreport_message" msgid="5212529146119624326">"This will collect information about your current device state, to send as an email message. It will take a little time from starting the bug report until it is ready to be sent. Please be patient."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"Interactive report"</string>
@@ -1767,12 +1765,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"The feature will open the next time that you tap the accessibility button"</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"The feature will open the next time that you use this shortcut. Swipe up with 2 fingers from the bottom of your screen and release quickly."</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"The feature will open the next time that you use this shortcut. Swipe up with 3 fingers from the bottom of your screen and release quickly."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Magnification"</string>
<string name="user_switched" msgid="7249833311585228097">"Current user <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="1912993630661332336">"Switching to <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2436,17 +2431,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"How it works"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Pending…"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Set up Fingerprint Unlock again"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> can no longer be recognised."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> and <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> can no longer be recognised."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"<xliff:g id="FINGERPRINT">%s</xliff:g> can no longer be recognised. Set up Fingerprint Unlock again."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> and <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> can no longer be recognised. Set up Fingerprint Unlock again."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"Set up Face Unlock again"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"Your face model can no longer be recognised. Set up Face Unlock again."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Set up"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Not now"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"Alarm for <xliff:g id="USER_NAME">%s</xliff:g>"</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 00b39a925c65..bd5976b66363 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -265,8 +265,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"Bug report"</string>
<string name="global_action_logout" msgid="6093581310002476511">"End session"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Screenshot"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"Bug report"</string>
<string name="bugreport_message" msgid="5212529146119624326">"This will collect information about your current device state, to send as an e-mail message. It will take a little time from starting the bug report until it is ready to be sent; please be patient."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"Interactive report"</string>
@@ -2427,17 +2425,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"How it works"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Pending..."</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Set up Fingerprint Unlock again"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> can no longer be recognized."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> and <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> can no longer be recognized."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"<xliff:g id="FINGERPRINT">%s</xliff:g> can no longer be recognized. Set up Fingerprint Unlock again."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> and <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> can no longer be recognized. Set up Fingerprint Unlock again."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"Set up Face Unlock again"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"Your face model can no longer be recognized. Set up Face Unlock again."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Set up"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Not now"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"Alarm for <xliff:g id="USER_NAME">%s</xliff:g>"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 0fff77a1faed..ad909ef87fd8 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -265,8 +265,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"Bug report"</string>
<string name="global_action_logout" msgid="6093581310002476511">"End session"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Screenshot"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"Bug report"</string>
<string name="bugreport_message" msgid="5212529146119624326">"This will collect information about your current device state, to send as an email message. It will take a little time from starting the bug report until it is ready to be sent. Please be patient."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"Interactive report"</string>
@@ -1767,12 +1765,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"The feature will open the next time that you tap the accessibility button"</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"The feature will open the next time that you use this shortcut. Swipe up with 2 fingers from the bottom of your screen and release quickly."</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"The feature will open the next time that you use this shortcut. Swipe up with 3 fingers from the bottom of your screen and release quickly."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Magnification"</string>
<string name="user_switched" msgid="7249833311585228097">"Current user <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="1912993630661332336">"Switching to <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2436,17 +2431,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"How it works"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Pending…"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Set up Fingerprint Unlock again"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> can no longer be recognised."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> and <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> can no longer be recognised."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"<xliff:g id="FINGERPRINT">%s</xliff:g> can no longer be recognised. Set up Fingerprint Unlock again."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> and <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> can no longer be recognised. Set up Fingerprint Unlock again."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"Set up Face Unlock again"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"Your face model can no longer be recognised. Set up Face Unlock again."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Set up"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Not now"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"Alarm for <xliff:g id="USER_NAME">%s</xliff:g>"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index ba7bc5f6f770..5fe0d321a356 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -265,8 +265,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"Bug report"</string>
<string name="global_action_logout" msgid="6093581310002476511">"End session"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Screenshot"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"Bug report"</string>
<string name="bugreport_message" msgid="5212529146119624326">"This will collect information about your current device state, to send as an email message. It will take a little time from starting the bug report until it is ready to be sent. Please be patient."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"Interactive report"</string>
@@ -1767,12 +1765,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"The feature will open the next time that you tap the accessibility button"</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"The feature will open the next time that you use this shortcut. Swipe up with 2 fingers from the bottom of your screen and release quickly."</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"The feature will open the next time that you use this shortcut. Swipe up with 3 fingers from the bottom of your screen and release quickly."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Magnification"</string>
<string name="user_switched" msgid="7249833311585228097">"Current user <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="1912993630661332336">"Switching to <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2436,17 +2431,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"How it works"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Pending…"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Set up Fingerprint Unlock again"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> can no longer be recognised."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> and <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> can no longer be recognised."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"<xliff:g id="FINGERPRINT">%s</xliff:g> can no longer be recognised. Set up Fingerprint Unlock again."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> and <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> can no longer be recognised. Set up Fingerprint Unlock again."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"Set up Face Unlock again"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"Your face model can no longer be recognised. Set up Face Unlock again."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Set up"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Not now"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"Alarm for <xliff:g id="USER_NAME">%s</xliff:g>"</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index 2798d032027d..1c0ea4b23958 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -265,8 +265,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‏‎‎‏‎‏‎‎‏‏‏‎‏‏‎‎‎‎‎‎‎‎‏‎‎‎‎‏‎‎‏‎‎‏‎‏‎‎‎‏‏‎‏‎‎‏‎‎‏‎‎‎‏‎‎‏‏‎Bug report‎‏‎‎‏‎"</string>
<string name="global_action_logout" msgid="6093581310002476511">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‎‎‏‎‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‎‏‎‎‎‎‏‎‏‎‏‎‎‎‎‎‏‏‎‏‎‏‏‏‎‏‏‏‏‏‎End session‎‏‎‎‏‎"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‎‎‏‏‏‎‎‎‏‏‎‎‎‏‎‏‏‏‎‎‏‏‎‎‎‏‏‏‏‏‏‏‎‎‎‎‏‎‎‎‏‎‏‏‎‎‎‎‎‏‏‎‎‏‎‎‎Screenshot‎‏‎‎‏‎"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‎‏‎‎‏‏‏‏‎‏‎‏‎‏‏‎‏‎‏‎‏‏‏‏‏‏‏‎‎‎‎‏‏‎‏‏‎‎‎‎‎‎‏‎‎‏‏‎‏‏‏‏‎‏‎‎Bug report‎‏‎‎‏‎"</string>
<string name="bugreport_message" msgid="5212529146119624326">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‎‎‏‎‏‎‏‏‎‏‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‎‎‏‎‎‏‏‏‏‏‎‏‎‏‎‎‏‎‎‏‎‏‏‎‏‎‎‎‎‏‏‎‎This will collect information about your current device state, to send as an e-mail message. It will take a little time from starting the bug report until it is ready to be sent; please be patient.‎‏‎‎‏‎"</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‎‏‎‏‎‏‎‎‎‎‏‎‏‏‏‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‎‏‎‎‎‏‎‎‎‎‎‏‏‎‏‎‏‏‏‏‏‎‎‏‎Interactive report‎‏‎‎‏‎"</string>
@@ -2427,17 +2425,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‏‎‏‏‏‎‏‏‏‎‏‎‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‎‏‎‎‎‏‎‏‏‏‏‎‎‏‏‎‎‎‎‏‏‎‎‎‎‏‏‏‎How it works‎‏‎‎‏‎"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‎‎‎‏‎‎‎‏‎‎‏‎‎‏‏‏‏‎‏‎‏‎‏‎‏‏‏‏‏‎‏‏‏‎‏‎‏‎‏‏‎‏‎‏‏‏‎‏‎‏‎‏‏‎‏‎Pending...‎‏‎‎‏‎"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‎‎‎‏‎‏‎‏‏‎‏‎‏‏‎‎‎‎‏‏‎‎‎‏‎‎‏‏‎‏‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‏‎‎‏‏‏‏‎‏‎‏‎Set up Fingerprint Unlock again‎‏‎‎‏‎"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‏‎‎‏‏‎‏‎‏‏‎‏‏‎‏‏‏‎‎‎‏‎‎‎‏‏‏‎‎‎‏‎‎‎‎‎‎‎‏‎‎‏‏‎‎‏‏‎‎‏‎‏‏‎‏‏‎‎‎‏‎‎‏‏‎<xliff:g id="FINGERPRINT">%s</xliff:g>‎‏‎‎‏‏‏‎ can no longer be recognized.‎‏‎‎‏‎"</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‎‏‎‏‎‏‎‏‏‎‎‏‏‏‎‏‎‏‎‎‏‎‎‏‏‎‎‏‏‎‏‏‏‎‏‎‎‎‎‏‎‎‎‎‎‏‎‎‏‏‎<xliff:g id="FINGERPRINT_0">%1$s</xliff:g>‎‏‎‎‏‏‏‎ and ‎‏‎‎‏‏‎<xliff:g id="FINGERPRINT_1">%2$s</xliff:g>‎‏‎‎‏‏‏‎ can no longer be recognized.‎‏‎‎‏‎"</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‏‎‏‎‏‎‎‏‏‎‎‎‎‏‎‎‏‎‏‏‏‎‎‏‏‏‎‏‏‎‎‏‏‎‏‎‏‎‏‏‏‎‏‎‏‎‎‏‏‏‎‏‎‏‎‏‎‎‎‏‎‎‏‏‎<xliff:g id="FINGERPRINT">%s</xliff:g>‎‏‎‎‏‏‏‎ can no longer be recognized. Set up Fingerprint Unlock again.‎‏‎‎‏‎"</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‎‏‏‏‎‏‎‏‎‎‎‏‏‏‏‏‏‎‎‏‏‏‏‎‎‎‎‎‏‎‏‏‎‎‎‎‎‎‎‎‏‎‏‎‎‏‎‎‏‏‏‎‏‏‎‏‏‎‎‏‎‎‏‏‎<xliff:g id="FINGERPRINT_0">%1$s</xliff:g>‎‏‎‎‏‏‏‎ and ‎‏‎‎‏‏‎<xliff:g id="FINGERPRINT_1">%2$s</xliff:g>‎‏‎‎‏‏‏‎ can no longer be recognized. Set up Fingerprint Unlock again.‎‏‎‎‏‎"</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‎‏‎‎‏‎‎‏‏‏‎‏‏‏‎‎‏‎‏‏‎‏‏‏‎‏‎‎‏‏‏‎‎‏‎‏‏‎‎‏‎‎‎‎‎‎‏‎‏‏‎‏‏‏‎‎‎‏‎Set up Face Unlock again‎‏‎‎‏‎"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‎‎‏‎‏‏‎‏‏‎‎‏‎‏‎‎‏‎‎‎‎‎‏‎‎‏‎‏‏‏‏‎‏‏‎‏‏‎‎‎‎‎‎‎‎‎‎‎‎‏‎‏‎‏‎‎‎‎Your face model can no longer be recognized. Set up Face Unlock again.‎‏‎‎‏‎"</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‎‎‏‏‏‎‎‏‎‏‏‎‏‎‎‏‎‎‎‏‏‏‎‎‎‏‏‏‏‏‎‎‏‎‎‎‏‎‏‏‎‏‎‏‏‏‏‎‎‏‏‏‎‏‎‎‏‎Set up‎‏‎‎‏‎"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‎‏‏‎‎‎‎‎‎‏‏‎‏‎‎‏‎‎‎‏‎‏‏‎‏‏‎‎‏‏‎‏‏‏‎‏‏‎‏‏‎‏‏‏‎‎‎‏‏‎‎‎‏‏‎Not now‎‏‎‎‏‎"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‎‏‏‏‎‎‎‎‏‏‎‏‏‎‏‎‏‏‏‎‎‎‎‎‏‏‎‎‎‏‏‎‏‎‎‏‏‎‏‎‏‏‏‏‎‎‎‏‎‏‏‏‎‎‏‏‏‎Alarm for ‎‏‎‎‏‏‎<xliff:g id="USER_NAME">%s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 543afeb70eaf..6f49b5487d47 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -266,8 +266,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"Informe de errores"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Finalizar sesión"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Captura de pantalla"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"Informe de errores"</string>
<string name="bugreport_message" msgid="5212529146119624326">"Se recopilará información sobre el estado actual de tu dispositivo, que se enviará por correo. Pasarán unos minutos desde que se inicie el informe de errores hasta que se envíe, por lo que te recomendamos que tengas paciencia."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"Informe interactivo"</string>
@@ -1768,12 +1766,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"La función se abrirá la próxima vez que presiones el botón de accesibilidad"</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"La función se abrirá la próxima vez que uses este atajo. Desliza hacia arriba con 2 dedos desde la parte inferior de la pantalla y levanta los dedos rápidamente."</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"La función se abrirá la próxima vez que uses este atajo. Desliza hacia arriba con 3 dedos desde la parte inferior de la pantalla y levanta los dedos rápidamente."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Ampliación"</string>
<string name="user_switched" msgid="7249833311585228097">"Usuario actual: <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="user_switching_message" msgid="1912993630661332336">"Cambiando a <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2437,17 +2432,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Cómo funciona"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Pendiente…"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Vuelve a configurar el Desbloqueo con huellas dactilares"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"Ya no se puede reconocer <xliff:g id="FINGERPRINT">%s</xliff:g>."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"Ya no se pueden reconocer <xliff:g id="FINGERPRINT_0">%1$s</xliff:g> y <xliff:g id="FINGERPRINT_1">%2$s</xliff:g>."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"Ya no se puede reconocer <xliff:g id="FINGERPRINT">%s</xliff:g>. Vuelve a configurar el Desbloqueo con huellas dactilares."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"Ya no se pueden reconocer <xliff:g id="FINGERPRINT_0">%1$s</xliff:g> y <xliff:g id="FINGERPRINT_1">%2$s</xliff:g>. Vuelve a configurar el Desbloqueo con huellas dactilares."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"Vuelve a configurar el Desbloqueo facial"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"Ya no se puede reconocer tu modelo de rostro. Vuelve a configurar el Desbloqueo facial."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Configurar"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Ahora no"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"Alarma para <xliff:g id="USER_NAME">%s</xliff:g>"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 0a153baa74aa..bd2a616478ac 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -266,8 +266,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"Informe de errores"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Finalizar sesión"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Captura de pantalla"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"Informe de errores"</string>
<string name="bugreport_message" msgid="5212529146119624326">"Se recopilará información sobre el estado actual de tu dispositivo y se enviará por correo electrónico. Pasarán unos minutos desde que empiece a generarse el informe de errores hasta que se envíe."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"Informe interactivo"</string>
@@ -1442,7 +1440,7 @@
<string name="fast_scroll_numeric_alphabet" msgid="2529539945421557329">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="alert_windows_notification_channel_group_name" msgid="6063891141815714246">"Mostrar sobre otras aplicaciones"</string>
<string name="alert_windows_notification_channel_name" msgid="3437528564303192620">"<xliff:g id="NAME">%s</xliff:g> se muestra sobre otras aplicaciones"</string>
- <string name="alert_windows_notification_title" msgid="6331662751095228536">"<xliff:g id="NAME">%s</xliff:g> se muestra sobre otras apps"</string>
+ <string name="alert_windows_notification_title" msgid="6331662751095228536">"<xliff:g id="NAME">%s</xliff:g> se muestra sobre otras aplicaciones"</string>
<string name="alert_windows_notification_message" msgid="6538171456970725333">"Si no quieres que <xliff:g id="NAME">%s</xliff:g> utilice esta función, toca la notificación para abrir los ajustes y desactivarla."</string>
<string name="alert_windows_notification_turn_off_action" msgid="7805857234839123780">"Desactivar"</string>
<string name="ext_media_checking_notification_title" msgid="8299199995416510094">"Comprobando <xliff:g id="NAME">%s</xliff:g>…"</string>
@@ -1768,12 +1766,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"La función se abrirá la próxima vez que toques el botón de accesibilidad"</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"La función se abrirá la próxima vez que uses este acceso directo. Desliza hacia arriba con 2 dedos desde la parte inferior de la pantalla y suelta rápidamente."</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"La función se abrirá la próxima vez que uses este acceso directo. Desliza hacia arriba con 3 dedos desde la parte inferior de la pantalla y suelta rápidamente."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Ampliación"</string>
<string name="user_switched" msgid="7249833311585228097">"Usuario actual: <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="user_switching_message" msgid="1912993630661332336">"Cambiando a <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2437,17 +2432,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Cómo funciona"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Pendiente..."</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Configura Desbloqueo con huella digital de nuevo"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> ya no puede reconocerse."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> y <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> ya no pueden reconocerse."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"<xliff:g id="FINGERPRINT">%s</xliff:g> ya no puede reconocerse. Vuelve a configurar Desbloqueo con huella digital."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> y <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> ya no pueden reconocerse. Vuelve a configurar Desbloqueo con huella digital."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"Configura Desbloqueo facial de nuevo"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"Tu modelo facial ya no puede reconocerse. Vuelve a configurar Desbloqueo facial."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Configurar"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Ahora no"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"Alarma para <xliff:g id="USER_NAME">%s</xliff:g>"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 4b81448cc288..36bca22a34e1 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -265,8 +265,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"Veaaruanne"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Seansi lõpp"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Ekraanipilt"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"Veaaruanne"</string>
<string name="bugreport_message" msgid="5212529146119624326">"Nii kogutakse teavet teie seadme praeguse oleku kohta, et saata see meilisõnumina. Enne kui saate veaaruande ära saata, võtab selle loomine natuke aega; varuge kannatust."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"Interakt. aruanne"</string>
@@ -1767,12 +1765,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"Funktsioon avaneb järgmine kord, kui puudutate juurdepääsetavuse nuppu"</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"Funktsioon avaneb järgmine kord, kui kasutate seda otseteed. Tõmmake kahe sõrmega ekraani allservast üles ja vabastage kiiresti."</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"Funktsioon avaneb järgmine kord, kui kasutate seda otseteed. Tõmmake kolme sõrmega ekraani allservast üles ja vabastage kiiresti."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Suurendus"</string>
<string name="user_switched" msgid="7249833311585228097">"Praegune kasutaja <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="1912993630661332336">"Üleminek kasutajale <xliff:g id="NAME">%1$s</xliff:g> ..."</string>
@@ -2436,17 +2431,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Tööpõhimõtted"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Ootel …"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Seadistage sõrmejäljega avamine uuesti"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"Sõrmejälge <xliff:g id="FINGERPRINT">%s</xliff:g> ei saa enam tuvastada."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"Sõrmejälgi <xliff:g id="FINGERPRINT_0">%1$s</xliff:g> ja <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> ei saa enam tuvastada."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"Sõrmejälge <xliff:g id="FINGERPRINT">%s</xliff:g> ei saa enam tuvastada. Seadistage sõrmejäljega avamine uuesti."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"Sõrmejälgi <xliff:g id="FINGERPRINT_0">%1$s</xliff:g> ja <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> ei saa enam tuvastada. Seadistage sõrmejäljega avamine uuesti."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"Seadistage näoga avamine uuesti"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"Teie näomudelit ei saa enam tuvastada. Seadistage näoga avamine uuesti."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Seadista"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Mitte praegu"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"Äratus kasutajale <xliff:g id="USER_NAME">%s</xliff:g>"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 16b956ec1e98..a16c56b34ecc 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -265,14 +265,12 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"Akatsen txostena"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Amaitu saioa"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Pantaila-argazkia"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"Akatsen txostena"</string>
<string name="bugreport_message" msgid="5212529146119624326">"Gailuaren oraingo egoerari buruzko informazioa bilduko da, mezu elektroniko gisa bidaltzeko. Minutu batzuk igaroko dira akatsen txostena sortzen hasten denetik bidaltzeko prest egon arte. Itxaron, mesedez."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"Txosten dinamikoa"</string>
<string name="bugreport_option_interactive_summary" msgid="8493795476325339542">"Aukera hau erabili beharko zenuke ia beti. Txostenaren jarraipena egin ahal izango duzu eta arazoari buruzko xehetasunak eman ahal izango dituzu. Baliteke gutxitan erabili behar izaten diren atalak ez agertzea, denbora aurrezteko."</string>
<string name="bugreport_option_full_title" msgid="7681035745950045690">"Txosten osoa"</string>
- <string name="bugreport_option_full_summary" msgid="1975130009258435885">"Erabili aukera hau sisteman ahalik eta traba gutxien eragiteko gailuak erantzuten ez duenean, mantsoegi dabilenean edo txosteneko atal guztiak behar dituzunean. Ez dizu uzten xehetasun gehiago idazten, ezta beste pantaila-argazkirik ateratzen ere."</string>
+ <string name="bugreport_option_full_summary" msgid="1975130009258435885">"Erabili aukera hau sistemaren interferentzia ahalik eta txikiena izateko gailuak erantzuten ez duenean, mantsoegi dabilenean edo txosteneko atal guztiak behar dituzunean. Ez dizu uzten xehetasun gehiago idazten, ezta beste pantaila-argazkirik ateratzen ere."</string>
<string name="bugreport_countdown" msgid="6418620521782120755">"{count,plural, =1{Akatsen txostenerako argazkia aterako da # segundo barru.}other{Akatsen txostenerako argazkia aterako da # segundo barru.}}"</string>
<string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Pantaila-argazkia egin da akatsen txostenarekin"</string>
<string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Ezin izan da egin pantaila-argazkia akatsen txostenarekin"</string>
@@ -1767,12 +1765,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"Erabilerraztasuna botoia sakatzen duzun hurrengoan irekiko da eginbidea"</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"Lasterbidea erabiltzen duzun hurrengoan irekiko da eginbidea. Pasatu 2 hatz pantailaren behealdetik gorantz eta askatu bizkor."</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"Lasterbidea erabiltzen duzun hurrengoan irekiko da eginbidea. Pasatu 3 hatz pantailaren behealdetik gorantz eta askatu bizkor."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Lupa"</string>
<string name="user_switched" msgid="7249833311585228097">"Erabiltzailea: <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="1912993630661332336">"\"<xliff:g id="NAME">%1$s</xliff:g>\" erabiltzailera aldatzen…"</string>
@@ -2436,17 +2431,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Nola funtzionatzen du?"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Zain…"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Konfiguratu berriro hatz-marka bidez desblokeatzeko eginbidea"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> ez da ezagutzen jada."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> eta <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> ez dira ezagutzen jada."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"<xliff:g id="FINGERPRINT">%s</xliff:g> ez da ezagutzen jada. Konfiguratu berriro hatz-marka bidez desblokeatzeko eginbidea."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> eta <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> ez dira ezagutzen jada. Konfiguratu berriro hatz-marka bidez desblokeatzeko eginbidea."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"Konfiguratu berriro aurpegi bidez desblokeatzeko eginbidea"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"Zure aurpegi-eredua ez da ezagutzen jada. Konfiguratu berriro aurpegi bidez desblokeatzeko eginbidea."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Konfiguratu"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Orain ez"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"<xliff:g id="USER_NAME">%s</xliff:g> erabiltzailearentzako alarma"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 71e776053403..3eeb78169d61 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -265,8 +265,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"گزارش اشکال"</string>
<string name="global_action_logout" msgid="6093581310002476511">"پایان جلسه"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"نماگرفت"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"گزارش اشکال"</string>
<string name="bugreport_message" msgid="5212529146119624326">"این گزارش اطلاعات مربوط به وضعیت دستگاه کنونی شما را جمع‌آوری می‌کند تا به‌صورت پیام ایمیل ارسال شود. از زمان شروع گزارش اشکال تا آماده شدن برای ارسال اندکی زمان می‌برد؛ لطفاً کمی صبر کنید."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"گزارش تعاملی"</string>
@@ -1767,12 +1765,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"دفعه بعد که روی دکمه دسترس‌پذیری تک‌ضرب بزنید، این ویژگی باز می‌شود"</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"دفعه بعد که از این میان‌بر استفاده کنید، این ویژگی باز می‌شود. با ۲ انگشت از پایین صفحه تند به بالا بکشید و سریع رها کنید."</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"دفعه بعد که از این میان‌بر استفاده کنید، این ویژگی باز می‌شود. با ۳ انگشت از پایین صفحه تند به بالا بکشید و سریع رها کنید."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"درشت‌نمایی"</string>
<string name="user_switched" msgid="7249833311585228097">"کاربر کنونی <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="1912993630661332336">"در حالت تغییر به <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2432,21 +2427,16 @@
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"به‌دلایل امنیتی، محتوای برنامه پس‌از هم‌رسانی صفحه‌نمایش پنهان می‌شود"</string>
<string name="satellite_notification_title" msgid="4026338973463121526">"به‌طور خودکار به ماهواره متصل شد"</string>
<string name="satellite_notification_summary" msgid="5207364139430767162">"‏می‌توانید بدون شبکه تلفن همراه یا Wi-Fi پیام ارسال و دریافت کنید"</string>
- <string name="satellite_notification_open_message" msgid="4149234979688273729">"باز کردن «پیام‌ها»"</string>
+ <string name="satellite_notification_open_message" msgid="4149234979688273729">"باز کردن «پیام‌نگار»"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"روش کار"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"درحال تعلیق…"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"راه‌اندازی مجدد «قفل‌گشایی با اثر انگشت»"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"‫<xliff:g id="FINGERPRINT">%s</xliff:g> دیگر قابل‌شناسایی نیست."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"‫<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> و <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> دیگر قابل‌شناسایی نیستند."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"‫<xliff:g id="FINGERPRINT">%s</xliff:g> دیگر قابل‌شناسایی نیست. «قفل‌گشایی با اثر انگشت» را دوباره راه‌اندازی کنید."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"‫<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> و <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> دیگر قابل‌شناسایی نیستند. «قفل‌گشایی با اثر انگشت» را دوباره راه‌اندازی کنید."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"راه‌اندازی مجدد «قفل‌گشایی با چهره»"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"مدل چهره‌تان دیگر قابل‌شناسایی نیست. «قفل‌گشایی با چهره» را دوباره راه‌اندازی کنید."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"راه‌اندازی"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"حالا نه"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"زنگ ساعت <xliff:g id="USER_NAME">%s</xliff:g>"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index e881a4cf29e0..0cb8ce06ef79 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -265,8 +265,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"Virheraportti"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Lopeta käyttökerta"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Kuvakaappaus"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"Virheraportti"</string>
<string name="bugreport_message" msgid="5212529146119624326">"Toiminto kerää tietoja laitteen tilasta ja lähettää ne sähköpostitse. Virheraportti on valmis lähetettäväksi hetken kuluttua - kiitos kärsivällisyydestäsi."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"Interaktiivinen"</string>
@@ -1767,12 +1765,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"Ominaisuus avautuu, kun seuraavan kerran napautat saavutettavuuspainiketta"</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"Ominaisuus avautuu, kun seuraavan kerran käytät tätä pikakomentoa. Pyyhkäise näytön alareunasta ylös kahdella sormella ja nosta sormet näytöltä nopeasti."</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"Ominaisuus avautuu, kun seuraavan kerran käytät tätä pikakomentoa. Pyyhkäise näytön alareunasta ylös kolmella sormella ja nosta sormet näytöltä nopeasti."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Suurennus"</string>
<string name="user_switched" msgid="7249833311585228097">"Nykyinen käyttäjä: <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="1912993630661332336">"Vaihdetaan käyttäjään <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2436,17 +2431,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Näin se toimii"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Odottaa…"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Ota sormenjälkiavaus uudelleen käyttöön"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> ei enää ole tunnistettavissa."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> ja <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> eivät enää ole tunnistettavissa."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"<xliff:g id="FINGERPRINT">%s</xliff:g> ei enää ole tunnistettavissa. Ota sormenjälkiavaus uudelleen käyttöön."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> ja <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> eivät enää ole tunnistettavissa. Ota sormenjälkiavaus uudelleen käyttöön."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"Ota kasvojentunnistusavaus uudelleen käyttöön"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"Kasvomallia ei enää tunnisteta. Ota kasvojentunnistusavaus uudelleen käyttöön."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Ota käyttöön"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Ei nyt"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"Hälytys: <xliff:g id="USER_NAME">%s</xliff:g>"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index f5fc6039c636..07cbbf1490a4 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -198,7 +198,7 @@
<string name="ssl_ca_cert_noti_by_administrator" msgid="4564941950768783879">"Par l\'administrateur de votre profil professionnel"</string>
<string name="ssl_ca_cert_noti_managed" msgid="217337232273211674">"Par <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="work_profile_deleted" msgid="5891181538182009328">"Profil professionnel supprimé"</string>
- <string name="work_profile_deleted_details" msgid="3773706828364418016">"Le profil professionnel de l\'application d\'administration est manquant ou corrompu. Votre profil professionnel et ses données connexes ont donc été supprimés. Communiquez avec votre administrateur pour obtenir de l\'assistance."</string>
+ <string name="work_profile_deleted_details" msgid="3773706828364418016">"Le profil professionnel de l\'appli d\'administration est manquant ou corrompu. Votre profil professionnel et ses données connexes ont donc été supprimés. Communiquez avec votre administrateur pour obtenir de l\'assistance."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Votre profil professionnel n\'est plus accessible sur cet appareil"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Trop de tentatives d\'entrée du mot de passe"</string>
<string name="device_ownership_relinquished" msgid="4080886992183195724">"L\'administrateur a libéré l\'appareil pour un usage personnel"</string>
@@ -206,7 +206,7 @@
<string name="private_space_deleted_by_admin_details" msgid="7007781735201818689">"Votre organisation n\'autorise pas les espaces privés sur cet appareil géré."</string>
<string name="network_logging_notification_title" msgid="554983187553845004">"L\'appareil est géré"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"Votre organisation gère cet appareil et peut surveiller le trafic réseau. Touchez ici pour obtenir plus d\'information."</string>
- <string name="location_changed_notification_title" msgid="3620158742816699316">"Les applications peuvent accéder à votre position"</string>
+ <string name="location_changed_notification_title" msgid="3620158742816699316">"Les applis peuvent accéder à votre position"</string>
<string name="location_changed_notification_text" msgid="7158423339982706912">"Communiquez avec votre administrateur informatique pour en savoir plus"</string>
<string name="geofencing_service" msgid="3826902410740315456">"Service de définition de limites géographiques"</string>
<string name="country_detector" msgid="7023275114706088854">"Détecteur de pays"</string>
@@ -218,14 +218,14 @@
<string name="device_policy_manager_service" msgid="5085762851388850332">"Service de gestionnaire Device Policy"</string>
<string name="music_recognition_manager_service" msgid="7481956037950276359">"Service de gestion de la reconnaissance musicale"</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"Le contenu de votre appareil sera effacé"</string>
- <string name="factory_reset_message" msgid="2657049595153992213">"Impossible d\'utiliser l\'application d\'administration. Les données de votre appareil vont maintenant être effacées.\n\nSi vous avez des questions, communiquez avec l\'administrateur de votre organisation."</string>
+ <string name="factory_reset_message" msgid="2657049595153992213">"Impossible d\'utiliser l\'appli d\'administration. Les données de votre appareil vont maintenant être effacées.\n\nSi vous avez des questions, communiquez avec l\'administrateur de votre organisation."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Impression désactivée par <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"Activer profil professionnel"</string>
- <string name="personal_apps_suspension_text" msgid="6115455688932935597">"Vos applications personnelles sont bloquées jusqu\'à ce que vous activiez votre profil professionnel"</string>
- <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Les applications personnelles seront bloquées le <xliff:g id="DATE">%1$s</xliff:g> à <xliff:g id="TIME">%2$s</xliff:g>. Votre administrateur informatique ne vous autorise pas à laisser votre profil professionnel désactivé pendant plus de <xliff:g id="NUMBER">%3$d</xliff:g> jours."</string>
+ <string name="personal_apps_suspension_text" msgid="6115455688932935597">"Vos applis personnelles sont bloquées jusqu\'à ce que vous activiez votre profil professionnel"</string>
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Les applis personnelles seront bloquées le <xliff:g id="DATE">%1$s</xliff:g> à <xliff:g id="TIME">%2$s</xliff:g>. Votre administrateur informatique ne vous autorise pas à laisser votre profil professionnel désactivé pendant plus de <xliff:g id="NUMBER">%3$d</xliff:g> jours."</string>
<string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Activer"</string>
<string name="work_profile_telephony_paused_title" msgid="7690804479291839519">"Les appels et messages sont désactivés"</string>
- <string name="work_profile_telephony_paused_text" msgid="8065762301100978221">"Vous avez mis en pause les applications professionnelles. Vous ne recevrez aucun appel téléphonique ni message texte."</string>
+ <string name="work_profile_telephony_paused_text" msgid="8065762301100978221">"Vous avez mis en pause les applis professionnelles. Vous ne recevrez aucun appel téléphonique ni message texte."</string>
<string name="work_profile_telephony_paused_turn_on_button" msgid="7542632318337068821">"Réact. applis pros"</string>
<string name="me" msgid="6207584824693813140">"Moi"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Options de la tablette"</string>
@@ -252,7 +252,7 @@
<string name="shutdown_confirm" product="default" msgid="136816458966692315">"Votre téléphone va s\'éteindre."</string>
<string name="shutdown_confirm_question" msgid="796151167261608447">"Voulez-vous éteindre l\'appareil?"</string>
<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="reboot_safemode_confirm" msgid="1658357874737219624">"Voulez-vous redémarrer en mode sans échec? Cette opération aura pour effet de désactiver toutes les applis 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 appli récente"</string>
<string name="global_actions" product="tablet" msgid="4412132498517933867">"Options de la tablette"</string>
@@ -266,8 +266,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"Rapport de bogue"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Fermer la session"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Capture d\'écran"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"Rapport de bogue"</string>
<string name="bugreport_message" msgid="5212529146119624326">"Cela permet de recueillir des informations concernant l\'état actuel de votre appareil. Ces informations sont ensuite envoyées sous forme de courriel. Merci de patienter pendant la préparation du rapport de bogue. Cette opération peut prendre quelques instants."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"Rapport interactif"</string>
@@ -305,13 +303,13 @@
<string name="notification_channel_alerts" msgid="5070241039583668427">"Alertes"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"Démo en magasin"</string>
<string name="notification_channel_usb" msgid="1528280969406244896">"Connexion USB"</string>
- <string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"Application en cours d\'exécution"</string>
- <string name="notification_channel_foreground_service" msgid="7102189948158885178">"Applications qui sollicitent la pile"</string>
+ <string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"Appli en cours d\'exécution"</string>
+ <string name="notification_channel_foreground_service" msgid="7102189948158885178">"Applis qui sollicitent la pile"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"Agrandissement"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"Usage des fonctionnalités d\'accessibilité"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"Écran"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> sollicite la pile"</string>
- <string name="foreground_service_apps_in_background" msgid="7340037176412387863">"<xliff:g id="NUMBER">%1$d</xliff:g> applications sollicitent la pile"</string>
+ <string name="foreground_service_apps_in_background" msgid="7340037176412387863">"<xliff:g id="NUMBER">%1$d</xliff:g> applis sollicitent la pile"</string>
<string name="foreground_service_tap_for_details" msgid="9078123626015586751">"Touchez pour afficher des détails sur l\'utilisation de la pile et des données"</string>
<string name="foreground_service_multiple_separator" msgid="5002287361849863168">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
<string name="safeMode" msgid="8974401416068943888">"Mode sans échec"</string>
@@ -367,282 +365,282 @@
<string name="dream_preview_title" msgid="5570751491996100804">"Aperçu, <xliff:g id="DREAM_NAME">%1$s</xliff:g>"</string>
<string name="dream_accessibility_action_click" msgid="7392398629967797805">"Ignorer"</string>
<string name="permlab_statusBar" msgid="8798267849526214017">"désactiver ou modifier la barre d\'état"</string>
- <string name="permdesc_statusBar" msgid="5809162768651019642">"Permet à l\'application de désactiver la barre d\'état, ou d\'ajouter et de supprimer des icônes système."</string>
+ <string name="permdesc_statusBar" msgid="5809162768651019642">"Permet à l\'appli de désactiver la barre d\'état, ou d\'ajouter et de supprimer des icônes système."</string>
<string name="permlab_statusBarService" msgid="2523421018081437981">"servir de barre d\'état"</string>
- <string name="permdesc_statusBarService" msgid="6652917399085712557">"Permet à l\'application de faire office de barre d\'état."</string>
+ <string name="permdesc_statusBarService" msgid="6652917399085712557">"Permet à l\'appli de faire office de barre d\'état."</string>
<string name="permlab_expandStatusBar" msgid="1184232794782141698">"agrandir ou réduire la barre d\'état"</string>
- <string name="permdesc_expandStatusBar" msgid="7180756900448498536">"Permet à l\'application de réduire ou de développer la barre d\'état."</string>
+ <string name="permdesc_expandStatusBar" msgid="7180756900448498536">"Permet à l\'appli de réduire ou de développer la barre d\'état."</string>
<string name="permlab_fullScreenIntent" msgid="4310888199502509104">"afficher les notifications en mode plein écran sur un appareil verrouillé"</string>
- <string name="permdesc_fullScreenIntent" msgid="1100721419406643997">"Permet à l\'application d\'afficher les notifications en mode plein écran sur un appareil verrouillé."</string>
+ <string name="permdesc_fullScreenIntent" msgid="1100721419406643997">"Permet à l\'appli d\'afficher les notifications en mode plein écran sur un appareil verrouillé."</string>
<string name="permlab_install_shortcut" msgid="7451554307502256221">"Installer des raccourcis"</string>
- <string name="permdesc_install_shortcut" msgid="4476328467240212503">"Permet à une application d\'ajouter des raccourcis sans l\'intervention de l\'utilisateur."</string>
+ <string name="permdesc_install_shortcut" msgid="4476328467240212503">"Permet à une appli d\'ajouter des raccourcis sans l\'intervention de l\'utilisateur."</string>
<string name="permlab_uninstall_shortcut" msgid="295263654781900390">"désinstaller des raccourcis"</string>
- <string name="permdesc_uninstall_shortcut" msgid="1924735350988629188">"Permet à l\'application de supprimer des raccourcis de la page d\'accueil sans intervention de l\'utilisateur."</string>
+ <string name="permdesc_uninstall_shortcut" msgid="1924735350988629188">"Permet à l\'appli de supprimer des raccourcis de la page d\'accueil sans intervention de l\'utilisateur."</string>
<string name="permlab_processOutgoingCalls" msgid="4075056020714266558">"transférer les appels sortants"</string>
- <string name="permdesc_processOutgoingCalls" msgid="7833149750590606334">"Permet à l\'application de lire le numéro composé lors d\'un appel sortant et lui donne la possibilité de rediriger l\'appel vers un autre numéro ou d\'abandonner l\'appel."</string>
+ <string name="permdesc_processOutgoingCalls" msgid="7833149750590606334">"Permet à l\'appli de lire le numéro composé lors d\'un appel sortant et lui donne la possibilité de rediriger l\'appel vers un autre numéro ou d\'abandonner l\'appel."</string>
<string name="permlab_answerPhoneCalls" msgid="4131324833663725855">"répondre aux appels téléphoniques"</string>
- <string name="permdesc_answerPhoneCalls" msgid="894386681983116838">"Permet à l\'application de répondre aux appels entrants."</string>
+ <string name="permdesc_answerPhoneCalls" msgid="894386681983116838">"Permet à l\'appli de répondre aux appels entrants."</string>
<string name="permlab_receiveSms" msgid="505961632050451881">"recevoir des messages texte"</string>
- <string name="permdesc_receiveSms" msgid="1797345626687832285">"Permet à l\'application de recevoir et de traiter les messages texte. Cette autorisation lui donne la possibilité de surveiller ou de supprimer les messages envoyés à votre appareil sans vous les montrer."</string>
+ <string name="permdesc_receiveSms" msgid="1797345626687832285">"Permet à l\'appli de recevoir et de traiter les messages texte. Cette autorisation lui donne la possibilité de surveiller ou de supprimer les messages envoyés à votre appareil sans vous les montrer."</string>
<string name="permlab_receiveMms" msgid="4000650116674380275">"recevoir des messages multimédias"</string>
- <string name="permdesc_receiveMms" msgid="958102423732219710">"Permet à l\'application de recevoir et de traiter les messages multimédias. Cette autorisation lui donne la possibilité de surveiller ou de supprimer les messages envoyés à votre appareil sans vous les montrer."</string>
+ <string name="permdesc_receiveMms" msgid="958102423732219710">"Permet à l\'appli de recevoir et de traiter les messages multimédias. Cette autorisation lui donne la possibilité de surveiller ou de supprimer les messages envoyés à votre appareil sans vous les montrer."</string>
<string name="permlab_bindCellBroadcastService" msgid="586746677002040651">"Transférer les messages de diffusion cellulaire"</string>
- <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Permet à l\'application d\'établir un lien avec le module de diffusion cellulaire afin de transférer les messages de diffusion cellulaire à mesure de leur réception. Dans certaines régions, des alertes de diffusion cellulaire sont envoyées afin de vous avertir de situations d\'urgence. Des applications malveillantes peuvent interférer avec les performances ou le fonctionnement de votre appareil lors de la réception d\'une alerte d\'urgence par diffusion cellulaire."</string>
+ <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Permet à l\'appli d\'établir un lien avec le module de diffusion cellulaire afin de transférer les messages de diffusion cellulaire à mesure de leur réception. Dans certaines régions, des alertes de diffusion cellulaire sont envoyées afin de vous avertir de situations d\'urgence. Des applis malveillantes peuvent interférer avec les performances ou le fonctionnement de votre appareil lors de la réception d\'une alerte d\'urgence par diffusion cellulaire."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Gérer les appels en cours"</string>
- <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Autorise une application à afficher les renseignements concernant les appels en cours sur votre appareil et à les gérer."</string>
+ <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Autorise une appli à afficher les renseignements concernant les appels en cours sur votre appareil et à les gérer."</string>
<string name="permlab_accessLastKnownCellId" msgid="7638226620825665130">"Accéder à la dernière identité cellulaire connue."</string>
- <string name="permdesc_accessLastKnownCellId" msgid="6664621339249308857">"Autorise une application à accéder à la dernière identité cellulaire connue fournie par la téléphonie."</string>
+ <string name="permdesc_accessLastKnownCellId" msgid="6664621339249308857">"Autorise une appli à accéder à la dernière identité cellulaire connue fournie par la téléphonie."</string>
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"lire les messages de diffusion cellulaire"</string>
- <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Permet à l\'application de lire les messages de diffusion cellulaire que votre appareil reçoit. Dans certaines zones géographiques, des alertes vous sont envoyées afin de vous prévenir en cas de situation d\'urgence. Des applications malveillantes peuvent venir perturber les performances ou le fonctionnement de votre appareil lors de la réception d\'un message de diffusion cellulaire."</string>
+ <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Permet à l\'appli de lire les messages de diffusion cellulaire que votre appareil reçoit. Dans certaines zones géographiques, des alertes vous sont envoyées afin de vous prévenir en cas de situation d\'urgence. Des applis malveillantes peuvent venir perturber les performances ou le fonctionnement de votre appareil lors de la réception d\'un message de diffusion cellulaire."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"lire les flux auxquels vous êtes abonné"</string>
- <string name="permdesc_subscribedFeedsRead" msgid="6911349196661811865">"Permet à l\'application d\'obtenir des données sur les flux en cours de synchronisation."</string>
+ <string name="permdesc_subscribedFeedsRead" msgid="6911349196661811865">"Permet à l\'appli d\'obtenir des données sur les flux en cours de synchronisation."</string>
<string name="permlab_sendSms" msgid="7757368721742014252">"envoyer et afficher des messages texte"</string>
- <string name="permdesc_sendSms" msgid="6757089798435130769">"Permet à l\'application d\'envoyer des messages texte. Cette autorisation peut entraîner des frais inattendus. Des applications malveillantes peuvent générer des frais en envoyant des messages sans votre consentement."</string>
+ <string name="permdesc_sendSms" msgid="6757089798435130769">"Permet à l\'appli d\'envoyer des messages texte. Cette autorisation peut entraîner des frais inattendus. Des applis malveillantes peuvent générer des frais en envoyant des messages sans votre consentement."</string>
<string name="permlab_readSms" msgid="5164176626258800297">"voir les messages texte ou multimédias"</string>
- <string name="permdesc_readSms" product="tablet" msgid="7912990447198112829">"Cette application peut lire tous les messages texte stockés sur votre tablette."</string>
- <string name="permdesc_readSms" product="tv" msgid="3054753345758011986">"Cette application peut lire tous les messages texte stockés sur votre appareil Android TV."</string>
- <string name="permdesc_readSms" product="default" msgid="774753371111699782">"Cette application peut lire tous les messages texte stockés sur votre téléphone."</string>
+ <string name="permdesc_readSms" product="tablet" msgid="7912990447198112829">"Cette appli peut lire tous les messages texte stockés sur votre tablette."</string>
+ <string name="permdesc_readSms" product="tv" msgid="3054753345758011986">"Cette appli peut lire tous les messages texte stockés sur votre appareil Android TV."</string>
+ <string name="permdesc_readSms" product="default" msgid="774753371111699782">"Cette appli peut lire tous les messages texte stockés sur votre téléphone."</string>
<string name="permlab_receiveWapPush" msgid="4223747702856929056">"recevoir des messages WAP"</string>
- <string name="permdesc_receiveWapPush" msgid="1638677888301778457">"Permet à l\'application de recevoir et de traiter les messages WAP. Cette autorisation lui donne la possibilité de surveiller ou de supprimer les messages envoyés à votre appareil sans vous les montrer."</string>
- <string name="permlab_getTasks" msgid="7460048811831750262">"récupérer les données des applications en cours d\'exécution"</string>
- <string name="permdesc_getTasks" msgid="7388138607018233726">"Permet à l\'application de récupérer des données sur des tâches en cours d\'exécution et récemment exécutées. L\'application est ainsi susceptible d\'obtenir des données concernant les applications utilisées sur l\'appareil."</string>
+ <string name="permdesc_receiveWapPush" msgid="1638677888301778457">"Permet à l\'appli de recevoir et de traiter les messages WAP. Cette autorisation lui donne la possibilité de surveiller ou de supprimer les messages envoyés à votre appareil sans vous les montrer."</string>
+ <string name="permlab_getTasks" msgid="7460048811831750262">"récupérer les données des applis en cours d\'exécution"</string>
+ <string name="permdesc_getTasks" msgid="7388138607018233726">"Permet à l\'appli de récupérer des données sur des tâches en cours d\'exécution et récemment exécutées. L\'appli est ainsi susceptible d\'obtenir des données concernant les applis utilisées sur l\'appareil."</string>
<string name="permlab_manageProfileAndDeviceOwners" msgid="639849495253987493">"gérer les propriétaires des profils et de l\'appareil"</string>
- <string name="permdesc_manageProfileAndDeviceOwners" msgid="7304240671781989283">"Autoriser les applications à définir les propriétaires des profils et celui de l\'appareil"</string>
- <string name="permlab_reorderTasks" msgid="7598562301992923804">"réorganiser les applications en cours d\'exécution"</string>
- <string name="permdesc_reorderTasks" msgid="8796089937352344183">"Permet à l\'application de déplacer les tâches au premier plan et en arrière-plan. L\'application peut procéder à ces opérations sans votre intervention."</string>
+ <string name="permdesc_manageProfileAndDeviceOwners" msgid="7304240671781989283">"Autoriser les applis à définir les propriétaires des profils et celui de l\'appareil"</string>
+ <string name="permlab_reorderTasks" msgid="7598562301992923804">"réorganiser les applis en cours d\'exécution"</string>
+ <string name="permdesc_reorderTasks" msgid="8796089937352344183">"Permet à l\'appli de déplacer les tâches au premier plan et en arrière-plan. L\'appli peut procéder à ces opérations sans votre intervention."</string>
<string name="permlab_enableCarMode" msgid="893019409519325311">"activer le mode voiture"</string>
- <string name="permdesc_enableCarMode" msgid="56419168820473508">"Permet à l\'application d\'activer le mode Voiture."</string>
- <string name="permlab_killBackgroundProcesses" msgid="6559320515561928348">"fermer les autres applications"</string>
- <string name="permdesc_killBackgroundProcesses" msgid="2357013583055434685">"Permet à l\'application de mettre fin aux processus d\'autres applications exécutés en arrière-plan. Cette autorisation peut interrompre l\'exécution d\'autres applications."</string>
- <string name="permlab_systemAlertWindow" msgid="5757218350944719065">"Cette application peut s\'afficher par-dessus d\'autres applications"</string>
- <string name="permdesc_systemAlertWindow" msgid="1145660714855738308">"Cette application peut s\'afficher par-dessus d\'autres applications ou parties de l\'écran. Cela pourrait interférer avec l\'utilisation normale des applications et modifier la manière dont les autres applications s\'affichent à l\'écran."</string>
- <string name="permlab_hideOverlayWindows" msgid="6382697828482271802">"Masquer les superpositions d\'autres applications"</string>
- <string name="permdesc_hideOverlayWindows" msgid="5660242821651958225">"Cette application peut demander au système de masquer les superpositions provenant d\'applications, afin qu\'elles ne s\'affichent pas au-dessus de celle-ci."</string>
+ <string name="permdesc_enableCarMode" msgid="56419168820473508">"Permet à l\'appli d\'activer le mode Voiture."</string>
+ <string name="permlab_killBackgroundProcesses" msgid="6559320515561928348">"fermer les autres applis"</string>
+ <string name="permdesc_killBackgroundProcesses" msgid="2357013583055434685">"Permet à l\'appli de mettre fin aux processus d\'autres applis exécutés en arrière-plan. Cette autorisation peut interrompre l\'exécution d\'autres applis."</string>
+ <string name="permlab_systemAlertWindow" msgid="5757218350944719065">"Cette appli peut s\'afficher par-dessus d\'autres applis"</string>
+ <string name="permdesc_systemAlertWindow" msgid="1145660714855738308">"Cette appli peut s\'afficher par-dessus d\'autres applis ou parties de l\'écran. Cela pourrait interférer avec l\'utilisation normale des applis et modifier la manière dont les autres applis s\'affichent à l\'écran."</string>
+ <string name="permlab_hideOverlayWindows" msgid="6382697828482271802">"Masquer les superpositions d\'autres applis"</string>
+ <string name="permdesc_hideOverlayWindows" msgid="5660242821651958225">"Cette appli peut demander au système de masquer les superpositions provenant d\'applis, afin qu\'elles ne s\'affichent pas au-dessus de celle-ci."</string>
<string name="permlab_runInBackground" msgid="541863968571682785">"fonctionner en arrière-plan"</string>
- <string name="permdesc_runInBackground" msgid="4344539472115495141">"Cette application peut fonctionner en arrière-plan. Cela risque d\'épuiser la pile plus rapidement."</string>
+ <string name="permdesc_runInBackground" msgid="4344539472115495141">"Cette appli peut fonctionner en arrière-plan. Cela risque d\'épuiser la pile plus rapidement."</string>
<string name="permlab_useDataInBackground" msgid="783415807623038947">"utiliser des données en arrière-plan"</string>
- <string name="permdesc_useDataInBackground" msgid="1230753883865891987">"Cette application peut utiliser des données en arrière-plan. Cela risque d\'augmenter l\'utilisation des données."</string>
+ <string name="permdesc_useDataInBackground" msgid="1230753883865891987">"Cette appli peut utiliser des données en arrière-plan. Cela risque d\'augmenter l\'utilisation des données."</string>
<string name="permlab_schedule_exact_alarm" msgid="6683283918033029730">"Programmer des actions à échéance précise"</string>
- <string name="permdesc_schedule_exact_alarm" msgid="8198009212013211497">"Cette application peut programmer des tâches à effectuer ultérieurement à un moment voulu. Cela implique que l\'application peut également s\'exécuter quand vous n\'utilisez pas activement l\'appareil."</string>
+ <string name="permdesc_schedule_exact_alarm" msgid="8198009212013211497">"Cette appli peut programmer des tâches à effectuer ultérieurement à un moment voulu. Cela implique que l\'appli peut également s\'exécuter quand vous n\'utilisez pas activement l\'appareil."</string>
<string name="permlab_use_exact_alarm" msgid="348045139777131552">"Programmer des alarmes ou des rappels d\'événements"</string>
- <string name="permdesc_use_exact_alarm" msgid="7033761461886938912">"Cette application peut programmer des actions, comme des alarmes et des rappels, pour vous avertir ultérieurement à un moment voulu."</string>
- <string name="permlab_persistentActivity" msgid="464970041740567970">"exécuter l\'application en continu"</string>
- <string name="permdesc_persistentActivity" product="tablet" msgid="6055271149187369916">"Permet à l\'application de rendre certains de ces composants persistants dans la mémoire. Cette autorisation peut limiter la mémoire disponible pour d\'autres applications et ralentir la tablette."</string>
- <string name="permdesc_persistentActivity" product="tv" msgid="6800526387664131321">"Permet à l\'application de rendre certains de ses composants persistants dans la mémoire. Cette autorisation peut limiter la mémoire disponible pour d\'autres applications et ralentir l\'appareil Android TV."</string>
- <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Permet à l\'application de rendre certains de ces composants persistants dans la mémoire. Cette autorisation peut limiter la mémoire disponible pour d\'autres applications et ralentir le téléphone."</string>
+ <string name="permdesc_use_exact_alarm" msgid="7033761461886938912">"Cette appli peut programmer des actions, comme des alarmes et des rappels, pour vous avertir ultérieurement à un moment voulu."</string>
+ <string name="permlab_persistentActivity" msgid="464970041740567970">"exécuter l\'appli en continu"</string>
+ <string name="permdesc_persistentActivity" product="tablet" msgid="6055271149187369916">"Permet à l\'appli de rendre certains de ces composants persistants dans la mémoire. Cette autorisation peut limiter la mémoire disponible pour d\'autres applis et ralentir la tablette."</string>
+ <string name="permdesc_persistentActivity" product="tv" msgid="6800526387664131321">"Permet à l\'appli de rendre certains de ses composants persistants dans la mémoire. Cette autorisation peut limiter la mémoire disponible pour d\'autres applis et ralentir l\'appareil Android TV."</string>
+ <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Permet à l\'appli de rendre certains de ces composants persistants dans la mémoire. Cette autorisation peut limiter la mémoire disponible pour d\'autres applis et ralentir le téléphone."</string>
<string name="permlab_foregroundService" msgid="1768855976818467491">"exécuter le service en premier plan"</string>
- <string name="permdesc_foregroundService" msgid="8720071450020922795">"Permet à l\'application d\'utiliser les services en premier plan."</string>
+ <string name="permdesc_foregroundService" msgid="8720071450020922795">"Permet à l\'appli d\'utiliser les services en premier plan."</string>
<string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"exécuter le service d\'avant-plan avec le type « appareil photo »"</string>
- <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"Autoriser l\'application à utiliser les services d\'avant-plan avec le type « appareil photo »"</string>
+ <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"Autoriser l\'appli à utiliser les services d\'avant-plan avec le type « appareil photo »"</string>
<string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"exécuter le service d\'avant-plan avec le type « appareil connecté »"</string>
- <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"Autoriser l\'application à utiliser les services d\'avant-plan avec le type « appareil connecté »"</string>
+ <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"Autoriser l\'appli à utiliser les services d\'avant-plan avec le type « appareil connecté »"</string>
<string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"exécuter le service d\'avant-plan avec le type « synchronisation des données »"</string>
- <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"Autoriser l\'application à utiliser les services d\'avant-plan avec le type « synchronisation des données »"</string>
+ <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"Autoriser l\'appli à utiliser les services d\'avant-plan avec le type « synchronisation des données »"</string>
<string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"exécuter le service d\'avant-plan avec le type « emplacement »"</string>
- <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"Autoriser l\'application à utiliser les services d\'avant-plan avec le type « emplacement »"</string>
+ <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"Autoriser l\'appli à utiliser les services d\'avant-plan avec le type « emplacement »"</string>
<string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"exécuter le service d\'avant-plan avec le type « lecture multimédia »"</string>
- <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"Autoriser l\'application à utiliser les services d\'avant-plan avec le type « lecture multimédia »"</string>
+ <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"Autoriser l\'appli à utiliser les services d\'avant-plan avec le type « lecture multimédia »"</string>
<string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"exécuter le service d\'avant-plan avec le type « projection de contenus multimédias »"</string>
- <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"Autoriser l\'application à utiliser les services d\'avant-plan avec le type « projection de contenus multimédias »"</string>
+ <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"Autoriser l\'appli à utiliser les services d\'avant-plan avec le type « projection de contenus multimédias »"</string>
<string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"exécuter le service d\'avant-plan avec le type « microphone »"</string>
- <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"Autoriser l\'application à utiliser les services d\'avant-plan avec le type « microphone »"</string>
+ <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"Autoriser l\'appli à utiliser les services d\'avant-plan avec le type « microphone »"</string>
<string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"exécuter le service d\'avant-plan avec le type « appel téléphonique »"</string>
- <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"Autoriser l\'application à utiliser les services d\'avant-plan avec le type « appel téléphonique »"</string>
+ <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"Autoriser l\'appli à utiliser les services d\'avant-plan avec le type « appel téléphonique »"</string>
<string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"exécuter le service d\'avant-plan avec le type « santé »"</string>
- <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"Autoriser l\'application à utiliser les services d\'avant-plan avec le type « santé »"</string>
+ <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"Autoriser l\'appli à utiliser les services d\'avant-plan avec le type « santé »"</string>
<string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"exécuter le service d\'avant-plan avec le type « messagerie à distance »"</string>
- <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"Autoriser l\'application à utiliser les services d\'avant-plan avec le type « messagerie à distance »"</string>
+ <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"Autoriser l\'appli à utiliser les services d\'avant-plan avec le type « messagerie à distance »"</string>
<string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"exécuter le service d\'avant-plan avec le type « système exempté »"</string>
- <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Autoriser l\'application à utiliser les services d\'avant-plan avec le type « système exempté »"</string>
+ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Autoriser l\'appli à utiliser les services d\'avant-plan avec le type « système exempté »"</string>
<string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"exécuter le service d\'avant-plan avec le type « fileManagement »"</string>
- <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"Autorise l\'application à utiliser les services d\'avant-plan avec le type « fileManagement »"</string>
+ <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"Autorise l\'appli à utiliser les services d\'avant-plan avec le type « fileManagement »"</string>
<string name="permlab_foregroundServiceMediaProcessing" msgid="3045295152245381864">"exécuter le service de premier plan avec le type « mediaProcessing »"</string>
- <string name="permdesc_foregroundServiceMediaProcessing" msgid="8303086172106677312">"Autorise l\'application à utiliser les services de premier plan avec le type « mediaProcessing »"</string>
+ <string name="permdesc_foregroundServiceMediaProcessing" msgid="8303086172106677312">"Autorise l\'appli à utiliser les services de premier plan avec le type « mediaProcessing »"</string>
<string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"exécuter le service d\'avant-plan avec le type « usage spécial »"</string>
- <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Autoriser l\'application à utiliser les services d\'avant-plan avec le type « usage spécial »"</string>
- <string name="permlab_getPackageSize" msgid="375391550792886641">"évaluer l\'espace de stockage de l\'application"</string>
- <string name="permdesc_getPackageSize" msgid="742743530909966782">"Permet à l\'application de récupérer la taille de son code, de ses données et de sa mémoire cache."</string>
+ <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Autoriser l\'appli à utiliser les services d\'avant-plan avec le type « usage spécial »"</string>
+ <string name="permlab_getPackageSize" msgid="375391550792886641">"évaluer l\'espace de stockage de l\'appli"</string>
+ <string name="permdesc_getPackageSize" msgid="742743530909966782">"Permet à l\'appli de récupérer la taille de son code, de ses données et de sa mémoire cache."</string>
<string name="permlab_writeSettings" msgid="8057285063719277394">"modifier les paramètres du système"</string>
- <string name="permdesc_writeSettings" msgid="8293047411196067188">"Permet à l\'application de modifier les paramètres du système. Des applications malveillantes peuvent utiliser cette fonctionnalité pour corrompre la configuration de votre système."</string>
+ <string name="permdesc_writeSettings" msgid="8293047411196067188">"Permet à l\'appli de modifier les paramètres du système. Des applis malveillantes peuvent utiliser cette fonctionnalité pour corrompre la configuration de votre système."</string>
<string name="permlab_receiveBootCompleted" msgid="6643339400247325379">"s\'exécuter au démarrage"</string>
- <string name="permdesc_receiveBootCompleted" product="tablet" msgid="5565659082718177484">"Permet à l\'application de se lancer une fois le démarrage du système terminé. Elle peut rallonger le temps de démarrage de la tablette et ralentir son fonctionnement global en raison de son exécution continue."</string>
- <string name="permdesc_receiveBootCompleted" product="tv" msgid="4900842256047614307">"Permet à l\'application de se lancer une fois le démarrage du système terminé. Cela peut rallonger le temps de démarrage de votre appareil Android TV et permettre à l\'application d\'en ralentir le fonctionnement global en raison de son exécution continue."</string>
- <string name="permdesc_receiveBootCompleted" product="default" msgid="7912677044558690092">"Permet à l\'application de se lancer une fois le démarrage du système terminé. Elle peut rallonger le temps de démarrage du téléphone et ralentir son fonctionnement global en raison de son exécution continue."</string>
+ <string name="permdesc_receiveBootCompleted" product="tablet" msgid="5565659082718177484">"Permet à l\'appli de se lancer une fois le démarrage du système terminé. Elle peut rallonger le temps de démarrage de la tablette et ralentir son fonctionnement global en raison de son exécution continue."</string>
+ <string name="permdesc_receiveBootCompleted" product="tv" msgid="4900842256047614307">"Permet à l\'appli de se lancer une fois le démarrage du système terminé. Cela peut rallonger le temps de démarrage de votre appareil Android TV et permettre à l\'appli d\'en ralentir le fonctionnement global en raison de son exécution continue."</string>
+ <string name="permdesc_receiveBootCompleted" product="default" msgid="7912677044558690092">"Permet à l\'appli de se lancer une fois le démarrage du système terminé. Elle peut rallonger le temps de démarrage du téléphone et ralentir son fonctionnement global en raison de son exécution continue."</string>
<string name="permlab_broadcastSticky" msgid="4552241916400572230">"envoyer une diffusion persistante"</string>
- <string name="permdesc_broadcastSticky" product="tablet" msgid="5058486069846384013">"Permet à l\'application d\'envoyer des intentions de diffusion \"persistantes\", qui perdurent une fois la diffusion terminée. Une utilisation excessive peut ralentir la tablette ou la rendre instable en l\'obligeant à utiliser trop de mémoire."</string>
- <string name="permdesc_broadcastSticky" product="tv" msgid="2338185920171000650">"Permet à l\'application d\'envoyer des intentions de diffusion persistantes, qui perdurent une fois la diffusion terminée. Une utilisation excessive peut ralentir votre appareil Android TV ou le rendre instable en l\'obligeant à utiliser trop de mémoire."</string>
- <string name="permdesc_broadcastSticky" product="default" msgid="134529339678913453">"Permet à l\'application d\'envoyer des intentions de diffusion \"persistantes\", qui perdurent une fois la diffusion terminée. Une utilisation excessive peut ralentir le téléphone ou le rendre instable en l\'obligeant à utiliser trop de mémoire."</string>
+ <string name="permdesc_broadcastSticky" product="tablet" msgid="5058486069846384013">"Permet à l\'appli d\'envoyer des intentions de diffusion \"persistantes\", qui perdurent une fois la diffusion terminée. Une utilisation excessive peut ralentir la tablette ou la rendre instable en l\'obligeant à utiliser trop de mémoire."</string>
+ <string name="permdesc_broadcastSticky" product="tv" msgid="2338185920171000650">"Permet à l\'appli d\'envoyer des intentions de diffusion persistantes, qui perdurent une fois la diffusion terminée. Une utilisation excessive peut ralentir votre appareil Android TV ou le rendre instable en l\'obligeant à utiliser trop de mémoire."</string>
+ <string name="permdesc_broadcastSticky" product="default" msgid="134529339678913453">"Permet à l\'appli d\'envoyer des intentions de diffusion \"persistantes\", qui perdurent une fois la diffusion terminée. Une utilisation excessive peut ralentir le téléphone ou le rendre instable en l\'obligeant à utiliser trop de mémoire."</string>
<string name="permlab_readContacts" msgid="8776395111787429099">"lire vos contacts"</string>
- <string name="permdesc_readContacts" product="tablet" msgid="6430093481659992692">"Permet à l\'application de lire les données relatives aux contacts stockés sur votre tablette. Les applications auront aussi accès aux comptes sur votre tablette qui ont créé des contacts. Cela peut comprendre des comptes créés par des applications que vous avez installées. Cette autorisation permet aux applications d\'enregistrer ces données. Les applications malveillantes peuvent les partager à votre insu."</string>
- <string name="permdesc_readContacts" product="tv" msgid="8400138591135554789">"Permet à l\'application de lire les données relatives aux contacts stockés sur votre appareil Android TV. Les applications auront aussi accès aux comptes sur votre appareil Android TV qui ont créé des contacts. Cela peut comprendre des comptes créés par des applications que vous avez installées. Cette autorisation permet aux applications d\'enregistrer ces données. Les applications malveillantes peuvent les partager à votre insu."</string>
- <string name="permdesc_readContacts" product="default" msgid="4911989776203207644">"Permet à l\'application de lire les données relatives aux contacts stockés sur votre téléphone. Les applications auront aussi accès aux comptes sur votre téléphone qui ont créé des contacts. Cela peut comprendre des comptes créés par des applications que vous avez installées. Cette autorisation permet aux applications d\'enregistrer ces données. Les applications malveillantes peuvent les partager à votre insu."</string>
+ <string name="permdesc_readContacts" product="tablet" msgid="6430093481659992692">"Permet à l\'appli de lire les données relatives aux contacts stockés sur votre tablette. Les applis auront aussi accès aux comptes sur votre tablette qui ont créé des contacts. Cela peut comprendre des comptes créés par des applis que vous avez installées. Cette autorisation permet aux applis d\'enregistrer ces données. Les applis malveillantes peuvent les partager à votre insu."</string>
+ <string name="permdesc_readContacts" product="tv" msgid="8400138591135554789">"Permet à l\'appli de lire les données relatives aux contacts stockés sur votre appareil Android TV. Les applis auront aussi accès aux comptes sur votre appareil Android TV qui ont créé des contacts. Cela peut comprendre des comptes créés par des applis que vous avez installées. Cette autorisation permet aux applis d\'enregistrer ces données. Les applis malveillantes peuvent les partager à votre insu."</string>
+ <string name="permdesc_readContacts" product="default" msgid="4911989776203207644">"Permet à l\'appli de lire les données relatives aux contacts stockés sur votre téléphone. Les applis auront aussi accès aux comptes sur votre téléphone qui ont créé des contacts. Cela peut comprendre des comptes créés par des applis que vous avez installées. Cette autorisation permet aux applis d\'enregistrer ces données. Les applis malveillantes peuvent les partager à votre insu."</string>
<string name="permlab_writeContacts" msgid="8919430536404830430">"modifier vos contacts"</string>
- <string name="permdesc_writeContacts" product="tablet" msgid="6422419281427826181">"Permet à l\'application de modifier les données relatives aux contacts stockés sur votre tablette. Cette autorisation permet aux applications de supprimer des données relatives aux contacts."</string>
- <string name="permdesc_writeContacts" product="tv" msgid="6488872735379978935">"Permet à l\'application de modifier les données relatives aux contacts stockés sur votre appareil Android TV. Cette autorisation permet aux applications de supprimer des données relatives aux contacts."</string>
- <string name="permdesc_writeContacts" product="default" msgid="8304795696237065281">"Permet à l\'application de modifier les données relatives aux contacts stockés sur votre téléphone. Cette autorisation permet aux applications de supprimer des données relatives aux contacts."</string>
+ <string name="permdesc_writeContacts" product="tablet" msgid="6422419281427826181">"Permet à l\'appli de modifier les données relatives aux contacts stockés sur votre tablette. Cette autorisation permet aux applis de supprimer des données relatives aux contacts."</string>
+ <string name="permdesc_writeContacts" product="tv" msgid="6488872735379978935">"Permet à l\'appli de modifier les données relatives aux contacts stockés sur votre appareil Android TV. Cette autorisation permet aux applis de supprimer des données relatives aux contacts."</string>
+ <string name="permdesc_writeContacts" product="default" msgid="8304795696237065281">"Permet à l\'appli de modifier les données relatives aux contacts stockés sur votre téléphone. Cette autorisation permet aux applis de supprimer des données relatives aux contacts."</string>
<string name="permlab_readCallLog" msgid="1739990210293505948">"lire le journal d\'appels"</string>
- <string name="permdesc_readCallLog" msgid="8964770895425873433">"Cette application peut lire votre historique d\'appel."</string>
+ <string name="permdesc_readCallLog" msgid="8964770895425873433">"Cette appli peut lire votre historique d\'appel."</string>
<string name="permlab_writeCallLog" msgid="670292975137658895">"modifier le journal d\'appels"</string>
- <string name="permdesc_writeCallLog" product="tablet" msgid="2657525794731690397">"Permet à l\'application de lire le journal d\'appels de votre tablette, y compris les données relatives aux appels entrants et sortants. Des applications malveillantes peuvent utiliser cette fonctionnalité pour effacer ou modifier votre journal d\'appels."</string>
- <string name="permdesc_writeCallLog" product="tv" msgid="3934939195095317432">"Permet à l\'application de modifier le journal d\'appels de votre appareil Android TV, y compris les données sur les appels entrants et sortants. Des applications malveillantes pourraient utiliser cette fonctionnalité pour effacer ou modifier votre journal d\'appels."</string>
- <string name="permdesc_writeCallLog" product="default" msgid="5903033505665134802">"Permet à l\'application de lire le journal d\'appels de votre téléphone, y compris les données relatives aux appels entrants et sortants. Des applications malveillantes peuvent utiliser cette fonctionnalité pour effacer ou modifier votre journal d\'appels."</string>
+ <string name="permdesc_writeCallLog" product="tablet" msgid="2657525794731690397">"Permet à l\'appli de lire le journal d\'appels de votre tablette, y compris les données relatives aux appels entrants et sortants. Des applis malveillantes peuvent utiliser cette fonctionnalité pour effacer ou modifier votre journal d\'appels."</string>
+ <string name="permdesc_writeCallLog" product="tv" msgid="3934939195095317432">"Permet à l\'appli de modifier le journal d\'appels de votre appareil Android TV, y compris les données sur les appels entrants et sortants. Des applis malveillantes pourraient utiliser cette fonctionnalité pour effacer ou modifier votre journal d\'appels."</string>
+ <string name="permdesc_writeCallLog" product="default" msgid="5903033505665134802">"Permet à l\'appli de lire le journal d\'appels de votre téléphone, y compris les données relatives aux appels entrants et sortants. Des applis malveillantes peuvent utiliser cette fonctionnalité pour effacer ou modifier votre journal d\'appels."</string>
<string name="permlab_bodySensors" msgid="662918578601619569">"Accéder aux données des capteurs corporels si en utilisation (fréq. card., etc.)"</string>
- <string name="permdesc_bodySensors" product="default" msgid="7652650410295512140">"Permet à l\'application d\'accéder aux données des capteurs corporels telles que la fréquence cardiaque, la température et le pourcentage d\'oxygène dans le sang pendant l\'utilisation de l\'application."</string>
+ <string name="permdesc_bodySensors" product="default" msgid="7652650410295512140">"Permet à l\'appli d\'accéder aux données des capteurs corporels telles que la fréquence cardiaque, la température et le pourcentage d\'oxygène dans le sang pendant l\'utilisation de l\'appli."</string>
<string name="permlab_bodySensors_background" msgid="4912560779957760446">"Accéder aux données des capteurs corporels (comme la fréq. card.) en arrière-plan"</string>
- <string name="permdesc_bodySensors_background" product="default" msgid="8870726027557749417">"Permet à l\'application d\'accéder aux données des capteurs corporels telles que la fréquence cardiaque, la température et le pourcentage d\'oxygène dans le sang pendant que l\'application s\'exécute en arrière-plan."</string>
+ <string name="permdesc_bodySensors_background" product="default" msgid="8870726027557749417">"Permet à l\'appli d\'accéder aux données des capteurs corporels telles que la fréquence cardiaque, la température et le pourcentage d\'oxygène dans le sang pendant que l\'appli s\'exécute en arrière-plan."</string>
<string name="permlab_readCalendar" msgid="6408654259475396200">"Lire les événements d\'agenda et leurs détails"</string>
- <string name="permdesc_readCalendar" product="tablet" msgid="515452384059803326">"Cette application peut lire tous les événements d\'agenda stockés sur votre tablette et partager ou enregistrer les données de votre agenda."</string>
- <string name="permdesc_readCalendar" product="tv" msgid="5811726712981647628">"Cette application peut lire tous les événements d\'agenda stockés sur votre appareil Android TV et partager ou enregistrer les données de votre agenda."</string>
- <string name="permdesc_readCalendar" product="default" msgid="9118823807655829957">"Cette application peut lire tous les événements d\'agenda stockés sur votre téléphone et partager ou enregistrer les données de votre agenda."</string>
+ <string name="permdesc_readCalendar" product="tablet" msgid="515452384059803326">"Cette appli peut lire tous les événements d\'agenda stockés sur votre tablette et partager ou enregistrer les données de votre agenda."</string>
+ <string name="permdesc_readCalendar" product="tv" msgid="5811726712981647628">"Cette appli peut lire tous les événements d\'agenda stockés sur votre appareil Android TV et partager ou enregistrer les données de votre agenda."</string>
+ <string name="permdesc_readCalendar" product="default" msgid="9118823807655829957">"Cette appli peut lire tous les événements d\'agenda stockés sur votre téléphone et partager ou enregistrer les données de votre agenda."</string>
<string name="permlab_writeCalendar" msgid="6422137308329578076">"ajouter ou modifier des événements d\'agenda et envoyer des courriels aux invités à l\'insu du propriétaire"</string>
- <string name="permdesc_writeCalendar" product="tablet" msgid="8722230940717092850">"Cette application peut ajouter, supprimer et modifier des événements d\'agenda sur votre tablette. Elle peut aussi envoyer des messages qui pourraient sembler venir des propriétaires d\'agenda en question ou modifier des événements sans avertir leur propriétaire."</string>
- <string name="permdesc_writeCalendar" product="tv" msgid="951246749004952706">"Cette application peut ajouter, supprimer et modifier des événements d\'agenda sur votre appareil Android TV. Elle peut aussi envoyer des messages qui pourraient sembler venir des propriétaires d\'agenda en question ou modifier des événements sans avertir leur propriétaire."</string>
- <string name="permdesc_writeCalendar" product="default" msgid="5416380074475634233">"Cette application peut ajouter, supprimer et modifier des événements d\'agenda sur votre téléphone. Elle peut aussi envoyer des messages qui pourraient sembler venir des propriétaires d\'agenda en question ou modifier des événements sans avertir leur propriétaire."</string>
+ <string name="permdesc_writeCalendar" product="tablet" msgid="8722230940717092850">"Cette appli peut ajouter, supprimer et modifier des événements d\'agenda sur votre tablette. Elle peut aussi envoyer des messages qui pourraient sembler venir des propriétaires d\'agenda en question ou modifier des événements sans avertir leur propriétaire."</string>
+ <string name="permdesc_writeCalendar" product="tv" msgid="951246749004952706">"Cette appli peut ajouter, supprimer et modifier des événements d\'agenda sur votre appareil Android TV. Elle peut aussi envoyer des messages qui pourraient sembler venir des propriétaires d\'agenda en question ou modifier des événements sans avertir leur propriétaire."</string>
+ <string name="permdesc_writeCalendar" product="default" msgid="5416380074475634233">"Cette appli peut ajouter, supprimer et modifier des événements d\'agenda sur votre téléphone. Elle peut aussi envoyer des messages qui pourraient sembler venir des propriétaires d\'agenda en question ou modifier des événements sans avertir leur propriétaire."</string>
<string name="permlab_accessLocationExtraCommands" msgid="5162339812057983988">"accéder aux commandes de fournisseur de position géographique supplémentaires"</string>
- <string name="permdesc_accessLocationExtraCommands" msgid="355369611979907967">"Permet à l\'application d\'accéder à des commandes de localisation supplémentaires offertes par le fournisseur. Elle est ainsi susceptible d\'interférer avec le bon fonctionnement du GPS ou de toute autre source de localisation."</string>
+ <string name="permdesc_accessLocationExtraCommands" msgid="355369611979907967">"Permet à l\'appli d\'accéder à des commandes de localisation supplémentaires offertes par le fournisseur. Elle est ainsi susceptible d\'interférer avec le bon fonctionnement du GPS ou de toute autre source de localisation."</string>
<string name="permlab_accessFineLocation" msgid="6426318438195622966">"accéder à votre position précise seulement en avant-plan"</string>
- <string name="permdesc_accessFineLocation" msgid="6732174080240016335">"Cette application peut obtenir votre position précise des services de localisation lorsque vous utilisez l\'application. Les services de localisation doivent être activés sur votre appareil pour que l\'application puisse obtenir votre position. Cela pourrait accroître l\'utilisation de la pile."</string>
+ <string name="permdesc_accessFineLocation" msgid="6732174080240016335">"Cette appli peut obtenir votre position précise des services de localisation lorsque vous utilisez l\'appli. Les services de localisation doivent être activés sur votre appareil pour que l\'appli puisse obtenir votre position. Cela pourrait accroître l\'utilisation de la pile."</string>
<string name="permlab_accessCoarseLocation" msgid="1561042925407799741">"accéder à votre position approximative seulement en avant-plan"</string>
- <string name="permdesc_accessCoarseLocation" msgid="778521847873199160">"Cette application peut obtenir votre position approximative des services de localisation lorsque vous utilisez l\'application. Les services de localisation doivent être activés sur votre appareil pour que l\'application puisse obtenir votre position."</string>
+ <string name="permdesc_accessCoarseLocation" msgid="778521847873199160">"Cette appli peut obtenir votre position approximative des services de localisation lorsque vous utilisez l\'appli. Les services de localisation doivent être activés sur votre appareil pour que l\'appli puisse obtenir votre position."</string>
<string name="permlab_accessBackgroundLocation" msgid="1721164702777366138">"accès à la localisation en arrière-plan"</string>
- <string name="permdesc_accessBackgroundLocation" msgid="8264885066095638105">"Cette application peut accéder à votre position en tout temps, même lorsque vous n\'utilisez pas l\'application."</string>
+ <string name="permdesc_accessBackgroundLocation" msgid="8264885066095638105">"Cette appli peut accéder à votre position en tout temps, même lorsque vous n\'utilisez pas l\'appli."</string>
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"modifier vos paramètres audio"</string>
- <string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Permet à l\'application de modifier les paramètres audio généraux, tels que le volume et la sortie audio utilisée."</string>
+ <string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Permet à l\'appli de modifier les paramètres audio généraux, tels que le volume et la sortie audio utilisée."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"enregistrer des fichiers audio"</string>
- <string name="permdesc_recordAudio" msgid="5857246765327514062">"Cette application peut enregistrer de l\'audio à l\'aide du microphone lorsque vous utilisez l\'application."</string>
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"Cette appli peut enregistrer de l\'audio à l\'aide du microphone lorsque vous utilisez l\'appli."</string>
<string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"enregistrer de l\'audio en arrière-plan"</string>
- <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Cette application peut enregistrer de l\'audio à l\'aide du microphone en tout temps."</string>
- <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"détecter les captures d\'écran des fenêtres d\'application"</string>
- <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"Cette application recevra une notification lorsqu\'une capture d\'écran sera prise pendant que l\'application est en cours d\'utilisation."</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Cette appli peut enregistrer de l\'audio à l\'aide du microphone en tout temps."</string>
+ <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"détecter les captures d\'écran des fenêtres d\'appli"</string>
+ <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"Cette appli recevra une notification lorsqu\'une capture d\'écran sera prise pendant que l\'appli est en cours d\'utilisation."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"envoyer des commandes à la carte SIM"</string>
- <string name="permdesc_sim_communication" msgid="4179799296415957960">"Permet à l\'application d\'envoyer des commandes à la carte SIM. Cette fonctionnalité est très dangereuse."</string>
+ <string name="permdesc_sim_communication" msgid="4179799296415957960">"Permet à l\'appli d\'envoyer des commandes à la carte SIM. Cette fonctionnalité est très dangereuse."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"reconnaître les activités physiques"</string>
- <string name="permdesc_activityRecognition" msgid="8667484762991357519">"Cette application peut reconnaître vos activités physiques."</string>
+ <string name="permdesc_activityRecognition" msgid="8667484762991357519">"Cette appli peut reconnaître vos activités physiques."</string>
<string name="permlab_camera" msgid="6320282492904119413">"prendre des photos et filmer des vidéos"</string>
- <string name="permdesc_camera" msgid="5240801376168647151">"Cette application peut prendre des photos et enregistrer des vidéos à l\'aide de l\'appareil photo lorsque vous utilisez l\'application."</string>
+ <string name="permdesc_camera" msgid="5240801376168647151">"Cette appli peut prendre des photos et enregistrer des vidéos à l\'aide de l\'appareil photo lorsque vous utilisez l\'appli."</string>
<string name="permlab_backgroundCamera" msgid="7549917926079731681">"prendre des photos et enregistrer des vidéos en arrière-plan"</string>
- <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"Cette application peut prendre des photos et enregistrer des vidéos à l\'aide de l\'appareil photo en tout temps."</string>
- <string name="permlab_systemCamera" msgid="3642917457796210580">"Autoriser une application ou un service à accéder aux appareils photo système pour prendre des photos et filmer des vidéos"</string>
- <string name="permdesc_systemCamera" msgid="5938360914419175986">"Cette application privilégiée ou système peut prendre des photos ou filmer des vidéos à l\'aide d\'un appareil photo système en tout temps. L\'application doit également posséder l\'autorisation android.permission.CAMERA"</string>
- <string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Autoriser une application ou un service de recevoir des rappels relatifs à l\'ouverture ou à la fermeture des appareils photos."</string>
- <string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"Cette application peut recevoir des rappels lorsque l\'appareil photo est ouvert ou fermé (par l\'application en question)."</string>
- <string name="permlab_cameraHeadlessSystemUser" msgid="680194666834500050">"Autoriser une application ou un service à accéder à la caméra en tant qu\'utilisateur de système sans interface."</string>
- <string name="permdesc_cameraHeadlessSystemUser" msgid="6963163319710996412">"Cette application peut accéder à la caméra en tant qu\'utilisateur de système sans interface."</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"Cette appli peut prendre des photos et enregistrer des vidéos à l\'aide de l\'appareil photo en tout temps."</string>
+ <string name="permlab_systemCamera" msgid="3642917457796210580">"Autoriser une appli ou un service à accéder aux appareils photo système pour prendre des photos et filmer des vidéos"</string>
+ <string name="permdesc_systemCamera" msgid="5938360914419175986">"Cette appli privilégiée ou système peut prendre des photos ou filmer des vidéos à l\'aide d\'un appareil photo système en tout temps. L\'appli doit également posséder l\'autorisation android.permission.CAMERA"</string>
+ <string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Autoriser une appli ou un service de recevoir des rappels relatifs à l\'ouverture ou à la fermeture des appareils photos."</string>
+ <string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"Cette appli peut recevoir des rappels lorsque l\'appareil photo est ouvert ou fermé (par l\'appli en question)."</string>
+ <string name="permlab_cameraHeadlessSystemUser" msgid="680194666834500050">"Autoriser une appli ou un service à accéder à la caméra en tant qu\'utilisateur de système sans interface."</string>
+ <string name="permdesc_cameraHeadlessSystemUser" msgid="6963163319710996412">"Cette appli peut accéder à la caméra en tant qu\'utilisateur de système sans interface."</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"gérer le vibreur"</string>
- <string name="permdesc_vibrate" msgid="8733343234582083721">"Permet à l\'application de gérer le vibreur de l\'appareil."</string>
- <string name="permdesc_vibrator_state" msgid="7050024956594170724">"Permet à l\'application d\'accéder au mode vibration."</string>
+ <string name="permdesc_vibrate" msgid="8733343234582083721">"Permet à l\'appli de gérer le vibreur de l\'appareil."</string>
+ <string name="permdesc_vibrator_state" msgid="7050024956594170724">"Permet à l\'appli d\'accéder au mode vibration."</string>
<string name="permlab_callPhone" msgid="1798582257194643320">"appeler directement des numéros de téléphone"</string>
- <string name="permdesc_callPhone" msgid="7892422187827695656">"Autorisez l\'application à appeler des numéros de téléphone sans votre intervention. Cela peut entraîner des frais ou des appels imprévus. Notez aussi que cela ne permet pas à l\'application d\'appeler des numéros d\'urgence. Des applications malveillantes peuvent engendrer des frais en passant des appels sans votre confirmation ou en composant des codes de fournisseurs de service qui transfèrent automatiquement des appels entrants vers un autre numéro."</string>
+ <string name="permdesc_callPhone" msgid="7892422187827695656">"Autorisez l\'appli à appeler des numéros de téléphone sans votre intervention. Cela peut entraîner des frais ou des appels imprévus. Notez aussi que cela ne permet pas à l\'appli d\'appeler des numéros d\'urgence. Des applis malveillantes peuvent engendrer des frais en passant des appels sans votre confirmation ou en composant des codes de fournisseurs de service qui transfèrent automatiquement des appels entrants vers un autre numéro."</string>
<string name="permlab_accessImsCallService" msgid="442192920714863782">"accéder au service d\'appel IMS"</string>
- <string name="permdesc_accessImsCallService" msgid="6328551241649687162">"Permet à l\'application d\'utiliser le service IMS pour faire des appels sans votre intervention."</string>
+ <string name="permdesc_accessImsCallService" msgid="6328551241649687162">"Permet à l\'appli d\'utiliser le service IMS pour faire des appels sans votre intervention."</string>
<string name="permlab_readPhoneState" msgid="8138526903259297969">"voir l\'état et l\'identité du téléphone"</string>
- <string name="permdesc_readPhoneState" msgid="7229063553502788058">"Permet à l\'application d\'accéder aux fonctionnalités téléphoniques de l\'appareil. Cette autorisation permet à l\'application de déterminer le numéro de téléphone et les identifiants de l\'appareil, si un appel est actif et le numéro distant connecté par un appel."</string>
+ <string name="permdesc_readPhoneState" msgid="7229063553502788058">"Permet à l\'appli d\'accéder aux fonctionnalités téléphoniques de l\'appareil. Cette autorisation permet à l\'appli de déterminer le numéro de téléphone et les identifiants de l\'appareil, si un appel est actif et le numéro distant connecté par un appel."</string>
<string name="permlab_readBasicPhoneState" msgid="3214853233263871347">"Lire l\'état et l\'identité de la téléphonie de base"</string>
- <string name="permdesc_readBasicPhoneState" msgid="828185691675460520">"Permet à l\'application d\'accéder aux fonctionnalités de téléphonie de base de l\'appareil."</string>
+ <string name="permdesc_readBasicPhoneState" msgid="828185691675460520">"Permet à l\'appli d\'accéder aux fonctionnalités de téléphonie de base de l\'appareil."</string>
<string name="permlab_manageOwnCalls" msgid="9033349060307561370">"acheminer les appels dans le système"</string>
- <string name="permdesc_manageOwnCalls" msgid="4431178362202142574">"Permet à l\'application d\'acheminer ses appels dans le système afin d\'améliorer l\'expérience d\'appel."</string>
+ <string name="permdesc_manageOwnCalls" msgid="4431178362202142574">"Permet à l\'appli d\'acheminer ses appels dans le système afin d\'améliorer l\'expérience d\'appel."</string>
<string name="permlab_callCompanionApp" msgid="3654373653014126884">"afficher et gérer les appels à l\'aide du système."</string>
- <string name="permdesc_callCompanionApp" msgid="8474168926184156261">"Autorise l\'application à afficher et à gérer les appels sortants sur l\'appareil. Cela comprend de l\'information comme les numéros pour les appels et l\'état des appels."</string>
+ <string name="permdesc_callCompanionApp" msgid="8474168926184156261">"Autorise l\'appli à afficher et à gérer les appels sortants sur l\'appareil. Cela comprend de l\'information comme les numéros pour les appels et l\'état des appels."</string>
<string name="permlab_exemptFromAudioRecordRestrictions" msgid="1164725468350759486">"est exemptée des restrictions relatives à l\'enregistrement de fichiers audio"</string>
- <string name="permdesc_exemptFromAudioRecordRestrictions" msgid="2425117015896871976">"Exempter l\'application des restrictions relatives à l\'enregistrement de fichiers audio."</string>
- <string name="permlab_acceptHandover" msgid="2925523073573116523">"continuer un appel d\'une autre application"</string>
- <string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Permet à l\'application de continuer un appel commencé dans une autre application."</string>
+ <string name="permdesc_exemptFromAudioRecordRestrictions" msgid="2425117015896871976">"Exempter l\'appli des restrictions relatives à l\'enregistrement de fichiers audio."</string>
+ <string name="permlab_acceptHandover" msgid="2925523073573116523">"continuer un appel d\'une autre appli"</string>
+ <string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Permet à l\'appli de continuer un appel commencé dans une autre appli."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"lire les numéros de téléphone"</string>
- <string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Permet à l\'application d\'accéder aux numéros de téléphone de l\'appareil."</string>
+ <string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Permet à l\'appli d\'accéder aux numéros de téléphone de l\'appareil."</string>
<string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"garder l\'écran de la voiture allumé"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"empêcher la tablette de passer en mode veille"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"Empêcher votre appareil Android TV de passer en mode Veille"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"empêcher le téléphone de passer en mode veille"</string>
- <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"Permet à l\'application de garder l\'écran de la voiture allumé."</string>
- <string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Permet à l\'application d\'empêcher la tablette de passer en mode veille."</string>
- <string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Permet à l\'application d\'empêcher votre appareil Android TV de passer en mode Veille."</string>
- <string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Permet à l\'application d\'empêcher le téléphone de passer en mode veille."</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"Permet à l\'appli de garder l\'écran de la voiture allumé."</string>
+ <string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Permet à l\'appli d\'empêcher la tablette de passer en mode veille."</string>
+ <string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Permet à l\'appli d\'empêcher votre appareil Android TV de passer en mode Veille."</string>
+ <string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Permet à l\'appli d\'empêcher le téléphone de passer en mode veille."</string>
<string name="permlab_transmitIr" msgid="8077196086358004010">"transmettre des signaux infrarouges"</string>
- <string name="permdesc_transmitIr" product="tablet" msgid="5884738958581810253">"Permet à l\'application d\'utiliser l\'émetteur infrarouge de la tablette."</string>
- <string name="permdesc_transmitIr" product="tv" msgid="3278506969529173281">"Permet à l\'application d\'utiliser le transmetteur infrarouge de votre appareil Android TV."</string>
- <string name="permdesc_transmitIr" product="default" msgid="8484193849295581808">"Permet à l\'application d\'utiliser l\'émetteur infrarouge du téléphone."</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5884738958581810253">"Permet à l\'appli d\'utiliser l\'émetteur infrarouge de la tablette."</string>
+ <string name="permdesc_transmitIr" product="tv" msgid="3278506969529173281">"Permet à l\'appli d\'utiliser le transmetteur infrarouge de votre appareil Android TV."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="8484193849295581808">"Permet à l\'appli d\'utiliser l\'émetteur infrarouge du téléphone."</string>
<string name="permlab_setWallpaper" msgid="6959514622698794511">"définir le fond d\'écran"</string>
- <string name="permdesc_setWallpaper" msgid="2973996714129021397">"Permet à l\'application de définir le fond d\'écran du système."</string>
+ <string name="permdesc_setWallpaper" msgid="2973996714129021397">"Permet à l\'appli de définir le fond d\'écran du système."</string>
<string name="permlab_accessHiddenProfile" msgid="8607094418491556823">"Accéder aux profils masqués"</string>
- <string name="permdesc_accessHiddenProfile" msgid="1543153202481009676">"Autorise l\'application à accéder aux profils masqués"</string>
+ <string name="permdesc_accessHiddenProfile" msgid="1543153202481009676">"Autorise l\'appli à accéder aux profils masqués"</string>
<string name="permlab_setWallpaperHints" msgid="1153485176642032714">"modifier la taille du fond d\'écran"</string>
- <string name="permdesc_setWallpaperHints" msgid="6257053376990044668">"Permet à l\'application de définir les bulles d\'aide concernant la taille du fond d\'écran du système."</string>
+ <string name="permdesc_setWallpaperHints" msgid="6257053376990044668">"Permet à l\'appli de définir les bulles d\'aide concernant la taille du fond d\'écran du système."</string>
<string name="permlab_setTimeZone" msgid="7922618798611542432">"définir le fuseau horaire"</string>
- <string name="permdesc_setTimeZone" product="tablet" msgid="1788868809638682503">"Permet à l\'application de modifier le fuseau horaire de la tablette."</string>
- <string name="permdesc_setTimeZone" product="tv" msgid="9069045914174455938">"Permet à l\'application de modifier le fuseau horaire de votre appareil Android TV."</string>
- <string name="permdesc_setTimeZone" product="default" msgid="4611828585759488256">"Permet à l\'application de modifier le fuseau horaire du téléphone."</string>
+ <string name="permdesc_setTimeZone" product="tablet" msgid="1788868809638682503">"Permet à l\'appli de modifier le fuseau horaire de la tablette."</string>
+ <string name="permdesc_setTimeZone" product="tv" msgid="9069045914174455938">"Permet à l\'appli de modifier le fuseau horaire de votre appareil Android TV."</string>
+ <string name="permdesc_setTimeZone" product="default" msgid="4611828585759488256">"Permet à l\'appli de modifier le fuseau horaire du téléphone."</string>
<string name="permlab_getAccounts" msgid="5304317160463582791">"rechercher des comptes sur l\'appareil"</string>
- <string name="permdesc_getAccounts" product="tablet" msgid="1784452755887604512">"Permet à l\'application d\'obtenir la liste des comptes connus par la tablette. Il peut s\'agir de n\'importe quel compte créé par les applications que vous avez installées."</string>
- <string name="permdesc_getAccounts" product="tv" msgid="437604680436540822">"Permet à l\'application d\'obtenir la liste des comptes connus de votre appareil Android TV. Cela peut comprendre n\'importe quel compte créé par les applications que vous avez installées."</string>
- <string name="permdesc_getAccounts" product="default" msgid="2491273043569751867">"Permet à l\'application d\'obtenir la liste des comptes connus par le téléphone. Il peut s\'agir de n\'importe quel compte créé par les applications que vous avez installées."</string>
+ <string name="permdesc_getAccounts" product="tablet" msgid="1784452755887604512">"Permet à l\'appli d\'obtenir la liste des comptes connus par la tablette. Il peut s\'agir de n\'importe quel compte créé par les applis que vous avez installées."</string>
+ <string name="permdesc_getAccounts" product="tv" msgid="437604680436540822">"Permet à l\'appli d\'obtenir la liste des comptes connus de votre appareil Android TV. Cela peut comprendre n\'importe quel compte créé par les applis que vous avez installées."</string>
+ <string name="permdesc_getAccounts" product="default" msgid="2491273043569751867">"Permet à l\'appli d\'obtenir la liste des comptes connus par le téléphone. Il peut s\'agir de n\'importe quel compte créé par les applis que vous avez installées."</string>
<string name="permlab_accessNetworkState" msgid="2349126720783633918">"afficher les connexions réseau"</string>
- <string name="permdesc_accessNetworkState" msgid="4394564702881662849">"Permet à l\'application d\'accéder à des détails concernant les connexions réseau, comme les réseaux existants et connectés."</string>
+ <string name="permdesc_accessNetworkState" msgid="4394564702881662849">"Permet à l\'appli d\'accéder à des détails concernant les connexions réseau, comme les réseaux existants et connectés."</string>
<string name="permlab_createNetworkSockets" msgid="3224420491603590541">"bénéficier d\'un accès complet au réseau"</string>
- <string name="permdesc_createNetworkSockets" msgid="7722020828749535988">"Permet à l\'application de créer des interfaces de connexion réseau et d\'utiliser des protocoles réseau personnalisés. Le navigateur et d\'autres applications permettent d\'envoyer des données sur Internet. Cette autorisation n\'est donc pas nécessaire pour envoyer des données sur Internet."</string>
+ <string name="permdesc_createNetworkSockets" msgid="7722020828749535988">"Permet à l\'appli de créer des interfaces de connexion réseau et d\'utiliser des protocoles réseau personnalisés. Le navigateur et d\'autres applis permettent d\'envoyer des données sur Internet. Cette autorisation n\'est donc pas nécessaire pour envoyer des données sur Internet."</string>
<string name="permlab_changeNetworkState" msgid="8945711637530425586">"modifier la connectivité réseau"</string>
- <string name="permdesc_changeNetworkState" msgid="649341947816898736">"Permet à l\'application de modifier l\'état de la connectivité réseau."</string>
+ <string name="permdesc_changeNetworkState" msgid="649341947816898736">"Permet à l\'appli de modifier l\'état de la connectivité réseau."</string>
<string name="permlab_changeTetherState" msgid="9079611809931863861">"changer la connectivité du partage de connexion"</string>
- <string name="permdesc_changeTetherState" msgid="3025129606422533085">"Permet à l\'application de modifier l\'état de la connectivité du partage de connexion."</string>
+ <string name="permdesc_changeTetherState" msgid="3025129606422533085">"Permet à l\'appli de modifier l\'état de la connectivité du partage de connexion."</string>
<string name="permlab_accessWifiState" msgid="5552488500317911052">"afficher les connexions Wi-Fi"</string>
- <string name="permdesc_accessWifiState" msgid="6913641669259483363">"Permet à l\'application d\'accéder à des détails sur les réseaux Wi-Fi afin de savoir si une connexion Wi-Fi est activée et pour connaître le nom des appareils connectés au Wi-Fi, par exemple."</string>
+ <string name="permdesc_accessWifiState" msgid="6913641669259483363">"Permet à l\'appli d\'accéder à des détails sur les réseaux Wi-Fi afin de savoir si une connexion Wi-Fi est activée et pour connaître le nom des appareils connectés au Wi-Fi, par exemple."</string>
<string name="permlab_changeWifiState" msgid="7947824109713181554">"activer/désactiver la connexion Wi-Fi"</string>
- <string name="permdesc_changeWifiState" msgid="7170350070554505384">"Permet à l\'application de se connecter à des points d\'accès Wi-Fi, de s\'en déconnecter et de modifier la configuration de l\'appareil pour les réseaux Wi-Fi."</string>
+ <string name="permdesc_changeWifiState" msgid="7170350070554505384">"Permet à l\'appli de se connecter à des points d\'accès Wi-Fi, de s\'en déconnecter et de modifier la configuration de l\'appareil pour les réseaux Wi-Fi."</string>
<string name="permlab_changeWifiMulticastState" msgid="285626875870754696">"autoriser la réception de données en mode Wi-Fi multidiffusion"</string>
- <string name="permdesc_changeWifiMulticastState" product="tablet" msgid="191079868596433554">"Permet à l\'application de recevoir des paquets envoyés à tous les appareils (et pas seulement à votre tablette) d\'un réseau Wi-Fi qui utilise des adresses de multidiffusion. Cette autorisation entraîne une consommation d\'énergie supérieure au mode de diffusion simple."</string>
- <string name="permdesc_changeWifiMulticastState" product="tv" msgid="1336952358450652595">"Permet à l\'application de recevoir des paquets envoyés à tous les appareils d\'un réseau Wi-Fi qui utilise des adresses de multidiffusion, et pas seulement à votre appareil Android TV. Cette autorisation entraîne une consommation d\'énergie supérieure au mode de diffusion simple."</string>
- <string name="permdesc_changeWifiMulticastState" product="default" msgid="8296627590220222740">"Permet à l\'application de recevoir des paquets envoyés à tous les appareils (et pas seulement à votre téléphone) d\'un réseau Wi-Fi qui utilise des adresses de multidiffusion. Cette autorisation entraîne une consommation d\'énergie supérieure au mode de diffusion simple."</string>
+ <string name="permdesc_changeWifiMulticastState" product="tablet" msgid="191079868596433554">"Permet à l\'appli de recevoir des paquets envoyés à tous les appareils (et pas seulement à votre tablette) d\'un réseau Wi-Fi qui utilise des adresses de multidiffusion. Cette autorisation entraîne une consommation d\'énergie supérieure au mode de diffusion simple."</string>
+ <string name="permdesc_changeWifiMulticastState" product="tv" msgid="1336952358450652595">"Permet à l\'appli de recevoir des paquets envoyés à tous les appareils d\'un réseau Wi-Fi qui utilise des adresses de multidiffusion, et pas seulement à votre appareil Android TV. Cette autorisation entraîne une consommation d\'énergie supérieure au mode de diffusion simple."</string>
+ <string name="permdesc_changeWifiMulticastState" product="default" msgid="8296627590220222740">"Permet à l\'appli de recevoir des paquets envoyés à tous les appareils (et pas seulement à votre téléphone) d\'un réseau Wi-Fi qui utilise des adresses de multidiffusion. Cette autorisation entraîne une consommation d\'énergie supérieure au mode de diffusion simple."</string>
<string name="permlab_bluetoothAdmin" msgid="6490373569441946064">"accéder aux paramètres Bluetooth"</string>
- <string name="permdesc_bluetoothAdmin" product="tablet" msgid="5370837055438574863">"Permet à l\'application de configurer la tablette Bluetooth locale, d\'identifier des appareils distants et de les associer à la tablette."</string>
- <string name="permdesc_bluetoothAdmin" product="tv" msgid="1623992984547014588">"Permet à l\'application de configurer le Bluetooth sur votre appareil Android TV, de repérer des appareils distants et de les associer à l\'appareil."</string>
- <string name="permdesc_bluetoothAdmin" product="default" msgid="7381341743021234863">"Permet à l\'application de configurer le téléphone Bluetooth local, d\'identifier des appareils distants et de les associer au téléphone."</string>
+ <string name="permdesc_bluetoothAdmin" product="tablet" msgid="5370837055438574863">"Permet à l\'appli de configurer la tablette Bluetooth locale, d\'identifier des appareils distants et de les associer à la tablette."</string>
+ <string name="permdesc_bluetoothAdmin" product="tv" msgid="1623992984547014588">"Permet à l\'appli de configurer le Bluetooth sur votre appareil Android TV, de repérer des appareils distants et de les associer à l\'appareil."</string>
+ <string name="permdesc_bluetoothAdmin" product="default" msgid="7381341743021234863">"Permet à l\'appli de configurer le téléphone Bluetooth local, d\'identifier des appareils distants et de les associer au téléphone."</string>
<string name="permlab_accessWimaxState" msgid="7029563339012437434">"se connecter au réseau WiMAX et s\'en déconnecter"</string>
- <string name="permdesc_accessWimaxState" msgid="5372734776802067708">"Permet à l\'application de déterminer si le WiMAX est activé et d\'obtenir des détails sur tous les réseaux WiMAX connectés."</string>
+ <string name="permdesc_accessWimaxState" msgid="5372734776802067708">"Permet à l\'appli de déterminer si le WiMAX est activé et d\'obtenir des détails sur tous les réseaux WiMAX connectés."</string>
<string name="permlab_changeWimaxState" msgid="6223305780806267462">"modifier l\'état du WiMAX"</string>
- <string name="permdesc_changeWimaxState" product="tablet" msgid="4011097664859480108">"Permet à l\'application de connecter la tablette aux réseaux WiMAX et de l\'en déconnecter."</string>
- <string name="permdesc_changeWimaxState" product="tv" msgid="5373274458799425276">"Permet à l\'application de connecter votre appareil Android TV aux réseaux WiMAX et de les en déconnecter."</string>
- <string name="permdesc_changeWimaxState" product="default" msgid="1551666203780202101">"Permet à l\'application de connecter le téléphone aux réseaux WiMAX et de l\'en déconnecter."</string>
+ <string name="permdesc_changeWimaxState" product="tablet" msgid="4011097664859480108">"Permet à l\'appli de connecter la tablette aux réseaux WiMAX et de l\'en déconnecter."</string>
+ <string name="permdesc_changeWimaxState" product="tv" msgid="5373274458799425276">"Permet à l\'appli de connecter votre appareil Android TV aux réseaux WiMAX et de les en déconnecter."</string>
+ <string name="permdesc_changeWimaxState" product="default" msgid="1551666203780202101">"Permet à l\'appli de connecter le téléphone aux réseaux WiMAX et de l\'en déconnecter."</string>
<string name="permlab_bluetooth" msgid="586333280736937209">"s\'associer à des appareils Bluetooth"</string>
- <string name="permdesc_bluetooth" product="tablet" msgid="3053222571491402635">"Permet à l\'application d\'accéder à la configuration du Bluetooth sur la tablette, et d\'établir et accepter des connexions avec les appareils associés."</string>
- <string name="permdesc_bluetooth" product="tv" msgid="8851534496561034998">"Permet à l\'application d\'afficher la configuration du Bluetooth sur votre appareil Android TV, de se connecter à des appareils associés et d\'accepter leur connexion."</string>
- <string name="permdesc_bluetooth" product="default" msgid="2779606714091276746">"Permet à l\'application d\'accéder à la configuration du Bluetooth sur le téléphone, et d\'établir et accepter des connexions avec les appareils associés."</string>
+ <string name="permdesc_bluetooth" product="tablet" msgid="3053222571491402635">"Permet à l\'appli d\'accéder à la configuration du Bluetooth sur la tablette, et d\'établir et accepter des connexions avec les appareils associés."</string>
+ <string name="permdesc_bluetooth" product="tv" msgid="8851534496561034998">"Permet à l\'appli d\'afficher la configuration du Bluetooth sur votre appareil Android TV, de se connecter à des appareils associés et d\'accepter leur connexion."</string>
+ <string name="permdesc_bluetooth" product="default" msgid="2779606714091276746">"Permet à l\'appli d\'accéder à la configuration du Bluetooth sur le téléphone, et d\'établir et accepter des connexions avec les appareils associés."</string>
<string name="permlab_bluetooth_scan" msgid="5402587142833124594">"découvrir des appareils Bluetooth et s\'y connecter"</string>
- <string name="permdesc_bluetooth_scan" product="default" msgid="6540723536925289276">"Permet à l\'application de découvrir les appareils Bluetooth à proximité et de s\'y connecter"</string>
+ <string name="permdesc_bluetooth_scan" product="default" msgid="6540723536925289276">"Permet à l\'appli de découvrir les appareils Bluetooth à proximité et de s\'y connecter"</string>
<string name="permlab_bluetooth_connect" msgid="6657463246355003528">"se connecter aux appareils Bluetooth associés"</string>
- <string name="permdesc_bluetooth_connect" product="default" msgid="4546016548795544617">"Permet à l\'application de se connecter aux appareils Bluetooth associés"</string>
+ <string name="permdesc_bluetooth_connect" product="default" msgid="4546016548795544617">"Permet à l\'appli de se connecter aux appareils Bluetooth associés"</string>
<string name="permlab_bluetooth_advertise" msgid="2781147747928853177">"envoyer annonces aux appareils Bluetooth à proxim."</string>
- <string name="permdesc_bluetooth_advertise" product="default" msgid="6085174451034210183">"Permet à l\'application d\'envoyer des annonces aux appareils Bluetooth à proximité"</string>
+ <string name="permdesc_bluetooth_advertise" product="default" msgid="6085174451034210183">"Permet à l\'appli d\'envoyer des annonces aux appareils Bluetooth à proximité"</string>
<string name="permlab_uwb_ranging" msgid="8141915781475770665">"déterminer la position relative entre des appareils à bande ultralarge à proximité"</string>
- <string name="permdesc_uwb_ranging" msgid="2519723069604307055">"Autorisez l\'application à déterminer la position relative entre des appareils à bande ultralarge à proximité"</string>
+ <string name="permdesc_uwb_ranging" msgid="2519723069604307055">"Autorisez l\'appli à déterminer la position relative entre des appareils à bande ultralarge à proximité"</string>
<string name="permlab_nearby_wifi_devices" msgid="392774237063608500">"interagir avec les appareils Wi-Fi à proximité"</string>
- <string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"Permet à l\'application de diffuser des annonces, de se connecter et de déterminer la position relative des appareils Wi-Fi à proximité"</string>
+ <string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"Permet à l\'appli de diffuser des annonces, de se connecter et de déterminer la position relative des appareils Wi-Fi à proximité"</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Information sur le service préféré de paiement CCP"</string>
- <string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Permet à l\'application d\'obtenir de l\'information sur le service préféré de paiement CCP comme les aides enregistrées et la route de destination."</string>
+ <string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Permet à l\'appli d\'obtenir de l\'information sur le service préféré de paiement CCP comme les aides enregistrées et la route de destination."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"gérer la communication en champ proche"</string>
- <string name="permdesc_nfc" msgid="8352737680695296741">"Permet à l\'application de communiquer avec des bornes, des cartes et des lecteurs compatibles avec la technologie CCP (communication en champ proche)."</string>
+ <string name="permdesc_nfc" msgid="8352737680695296741">"Permet à l\'appli de communiquer avec des bornes, des cartes et des lecteurs compatibles avec la technologie CCP (communication en champ proche)."</string>
<string name="permlab_nfcTransactionEvent" msgid="5868209446710407679">"Événement de transaction relatif à un élément sécurisé"</string>
- <string name="permdesc_nfcTransactionEvent" msgid="1904286701876487397">"Autorise l\'application à recevoir des informations relatives aux transactions effectuées sur un élément sécurisé."</string>
+ <string name="permdesc_nfcTransactionEvent" msgid="1904286701876487397">"Autorise l\'appli à recevoir des informations relatives aux transactions effectuées sur un élément sécurisé."</string>
<string name="permlab_disableKeyguard" msgid="3605253559020928505">"désactiver le verrouillage de l\'écran"</string>
- <string name="permdesc_disableKeyguard" msgid="3223710003098573038">"Permet à l\'application de désactiver le verrouillage des touches et toute mesure de sécurité par mot de passe associée. Par exemple, votre téléphone désactive le verrouillage des touches lorsque vous recevez un appel, puis le réactive lorsque vous raccrochez."</string>
+ <string name="permdesc_disableKeyguard" msgid="3223710003098573038">"Permet à l\'appli de désactiver le verrouillage des touches et toute mesure de sécurité par mot de passe associée. Par exemple, votre téléphone désactive le verrouillage des touches lorsque vous recevez un appel, puis le réactive lorsque vous raccrochez."</string>
<string name="permlab_requestPasswordComplexity" msgid="1808977190557794109">"demander la complexité du verrouillage d\'écran"</string>
- <string name="permdesc_requestPasswordComplexity" msgid="1130556896836258567">"Autorise l\'application à apprendre le niveau de complexité de l\'écran de verrouillage (élevé, moyen, faible ou aucun), qui indique la gamme possible de longueur et de type de verrouillage d\'écran. L\'application peut aussi suggérer aux utilisateurs de mettre à jour l\'écran de verrouillage afin d\'utiliser un certain niveau de complexité, mais ils peuvent ignorer la suggestion. Notez que le verrouillage d\'écran n\'est pas stocké en texte brut pour de manière à ce que l\'application n\'ait pas accès au mot de passe exact."</string>
+ <string name="permdesc_requestPasswordComplexity" msgid="1130556896836258567">"Autorise l\'appli à apprendre le niveau de complexité de l\'écran de verrouillage (élevé, moyen, faible ou aucun), qui indique la gamme possible de longueur et de type de verrouillage d\'écran. L\'appli peut aussi suggérer aux utilisateurs de mettre à jour l\'écran de verrouillage afin d\'utiliser un certain niveau de complexité, mais ils peuvent ignorer la suggestion. Notez que le verrouillage d\'écran n\'est pas stocké en texte brut pour de manière à ce que l\'appli n\'ait pas accès au mot de passe exact."</string>
<string name="permlab_postNotification" msgid="4875401198597803658">"afficher les notifications"</string>
- <string name="permdesc_postNotification" msgid="5974977162462877075">"Permet à l\'application d\'afficher les notifications"</string>
+ <string name="permdesc_postNotification" msgid="5974977162462877075">"Permet à l\'appli d\'afficher les notifications"</string>
<string name="permlab_turnScreenOn" msgid="219344053664171492">"allumer l\'écran"</string>
- <string name="permdesc_turnScreenOn" msgid="4394606875897601559">"Permet à l\'application d\'allumer l\'écran."</string>
+ <string name="permdesc_turnScreenOn" msgid="4394606875897601559">"Permet à l\'appli d\'allumer l\'écran."</string>
<string name="permlab_useBiometric" msgid="6314741124749633786">"utiliser le matériel biométrique"</string>
- <string name="permdesc_useBiometric" msgid="7502858732677143410">"Permet à l\'application d\'utiliser du matériel biométrique pour l\'authentification"</string>
+ <string name="permdesc_useBiometric" msgid="7502858732677143410">"Permet à l\'appli d\'utiliser du matériel biométrique pour l\'authentification"</string>
<string name="permlab_manageFingerprint" msgid="7432667156322821178">"gérer le lecteur d\'empreintes digitales"</string>
- <string name="permdesc_manageFingerprint" msgid="2025616816437339865">"Permet à l\'application de faire appel à des méthodes d\'ajout et de suppression de modèles d\'empreinte digitale que vous pouvez utiliser."</string>
+ <string name="permdesc_manageFingerprint" msgid="2025616816437339865">"Permet à l\'appli de faire appel à des méthodes d\'ajout et de suppression de modèles d\'empreinte digitale que vous pouvez utiliser."</string>
<string name="permlab_useFingerprint" msgid="1001421069766751922">"utiliser le lecteur d\'empreintes digitales"</string>
- <string name="permdesc_useFingerprint" msgid="412463055059323742">"Permet à l\'application d\'utiliser le lecteur d\'empreintes digitales pour l\'authentification"</string>
+ <string name="permdesc_useFingerprint" msgid="412463055059323742">"Permet à l\'appli d\'utiliser le lecteur d\'empreintes digitales pour l\'authentification"</string>
<string name="permlab_audioWrite" msgid="8501705294265669405">"modifier votre collection de musique"</string>
- <string name="permdesc_audioWrite" msgid="8057399517013412431">"Autorise l\'application à modifier votre collection de musique."</string>
+ <string name="permdesc_audioWrite" msgid="8057399517013412431">"Autorise l\'appli à modifier votre collection de musique."</string>
<string name="permlab_videoWrite" msgid="5940738769586451318">"modifier votre collection de vidéos"</string>
- <string name="permdesc_videoWrite" msgid="6124731210613317051">"Autorise l\'application à modifier votre collection de vidéos."</string>
+ <string name="permdesc_videoWrite" msgid="6124731210613317051">"Autorise l\'appli à modifier votre collection de vidéos."</string>
<string name="permlab_imagesWrite" msgid="1774555086984985578">"modifier votre collection de photos"</string>
- <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Autorise l\'application à modifier votre collection de photos."</string>
+ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Autorise l\'appli à modifier votre collection de photos."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"lire les positions issues de votre collection multimédia"</string>
- <string name="permdesc_mediaLocation" msgid="597912899423578138">"Autorise l\'application à lire les positions indiquées dans votre collection multimédia."</string>
+ <string name="permdesc_mediaLocation" msgid="597912899423578138">"Autorise l\'appli à lire les positions indiquées dans votre collection multimédia."</string>
<string name="biometric_app_setting_name" msgid="3339209978734534457">"Utiliser les données biométriques"</string>
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Utiliser les données biométriques ou le verrouillage de l\'écran"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Confirmez que c\'est vous"</string>
@@ -760,81 +758,81 @@
<string name="face_error_vendor_unknown" msgid="7387005932083302070">"Un problème est survenu. Réessayez."</string>
<string name="face_icon_content_description" msgid="465030547475916280">"Icône visage"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"lire les paramètres de synchronisation"</string>
- <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Permet à l\'application d\'accéder aux paramètres de synchronisation d\'un compte. Par exemple, cette autorisation peut permettre de déterminer si l\'application Contacts est synchronisée avec un compte ou non."</string>
+ <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Permet à l\'appli d\'accéder aux paramètres de synchronisation d\'un compte. Par exemple, cette autorisation peut permettre de déterminer si l\'appli Contacts est synchronisée avec un compte ou non."</string>
<string name="permlab_writeSyncSettings" msgid="6583154300780427399">"activer ou désactiver la synchronisation"</string>
- <string name="permdesc_writeSyncSettings" msgid="6029151549667182687">"Permet à une application de modifier les paramètres de synchronisation d\'un compte. Cette autorisation peut, par exemple, être utilisée pour activer la synchronisation de l\'application Contacts avec un compte."</string>
+ <string name="permdesc_writeSyncSettings" msgid="6029151549667182687">"Permet à une appli de modifier les paramètres de synchronisation d\'un compte. Cette autorisation peut, par exemple, être utilisée pour activer la synchronisation de l\'appli Contacts avec un compte."</string>
<string name="permlab_readSyncStats" msgid="3747407238320105332">"lire les statistiques de synchronisation"</string>
- <string name="permdesc_readSyncStats" msgid="3867809926567379434">"Permet à une application d\'accéder aux statistiques de synchronisation d\'un compte, y compris l\'historique des événements de synchronisation et le volume de données synchronisées."</string>
+ <string name="permdesc_readSyncStats" msgid="3867809926567379434">"Permet à une appli d\'accéder aux statistiques de synchronisation d\'un compte, y compris l\'historique des événements de synchronisation et le volume de données synchronisées."</string>
<string name="permlab_sdcardRead" msgid="5791467020950064920">"lire le contenu de votre espace de stockage partagé"</string>
- <string name="permdesc_sdcardRead" msgid="6872973242228240382">"Permet à l\'application de lire le contenu de votre espace de stockage partagé."</string>
+ <string name="permdesc_sdcardRead" msgid="6872973242228240382">"Permet à l\'appli de lire le contenu de votre espace de stockage partagé."</string>
<string name="permlab_readMediaAudio" msgid="8723513075731763810">"lire des fichiers audio à partir de l\'espace de stockage partagé"</string>
- <string name="permdesc_readMediaAudio" msgid="5299772574434619399">"Permet à l\'application de lire les fichiers audio de votre espace de stockage partagé."</string>
+ <string name="permdesc_readMediaAudio" msgid="5299772574434619399">"Permet à l\'appli de lire les fichiers audio de votre espace de stockage partagé."</string>
<string name="permlab_readMediaVideo" msgid="7768003311260655007">"lire des fichiers vidéo à partir de l\'espace de stockage partagé"</string>
- <string name="permdesc_readMediaVideo" msgid="3846400073770403528">"Permet à l\'application de lire les fichiers vidéo de votre espace de stockage partagé."</string>
+ <string name="permdesc_readMediaVideo" msgid="3846400073770403528">"Permet à l\'appli de lire les fichiers vidéo de votre espace de stockage partagé."</string>
<string name="permlab_readMediaImages" msgid="4057590631020986789">"lire des fichiers d\'image à partir de l\'espace de stockage partagé"</string>
- <string name="permdesc_readMediaImages" msgid="5836219373138469259">"Permet à l\'application de lire les fichiers d\'image de votre espace de stockage partagé."</string>
+ <string name="permdesc_readMediaImages" msgid="5836219373138469259">"Permet à l\'appli de lire les fichiers d\'image de votre espace de stockage partagé."</string>
<string name="permlab_readVisualUserSelect" msgid="5516204215354667586">"lire les fichiers d\'images et de vidéos sélectionnés par l\'utilisateur dans l\'espace de stockage partagé"</string>
- <string name="permdesc_readVisualUserSelect" msgid="8027174717714968217">"Permet à l\'application de lire les fichiers d\'images et de vidéos que vous sélectionnez dans votre espace de stockage partagé."</string>
+ <string name="permdesc_readVisualUserSelect" msgid="8027174717714968217">"Permet à l\'appli de lire les fichiers d\'images et de vidéos que vous sélectionnez dans votre espace de stockage partagé."</string>
<string name="permlab_sdcardWrite" msgid="4863021819671416668">"modifier ou supprimer le contenu de votre espace de stockage partagé"</string>
- <string name="permdesc_sdcardWrite" msgid="8376047679331387102">"Autorise l\'application à écrire le contenu de votre espace de stockage partagé."</string>
+ <string name="permdesc_sdcardWrite" msgid="8376047679331387102">"Autorise l\'appli à écrire le contenu de votre espace de stockage partagé."</string>
<string name="permlab_use_sip" msgid="8250774565189337477">"faire et recevoir des appels SIP"</string>
- <string name="permdesc_use_sip" msgid="3590270893253204451">"Autorise l\'application à effectuer et à recevoir des appels SIP."</string>
+ <string name="permdesc_use_sip" msgid="3590270893253204451">"Autorise l\'appli à effectuer et à recevoir des appels SIP."</string>
<string name="permlab_register_sim_subscription" msgid="1653054249287576161">"enregistrer de nouvelles connexions de télécommunication à l\'aide de la carte SIM"</string>
- <string name="permdesc_register_sim_subscription" msgid="4183858662792232464">"Permettre à l\'application d\'enregistrer de nouvelles connexions de télécommunication à l\'aide de la carte SIM"</string>
+ <string name="permdesc_register_sim_subscription" msgid="4183858662792232464">"Permettre à l\'appli d\'enregistrer de nouvelles connexions de télécommunication à l\'aide de la carte SIM"</string>
<string name="permlab_register_call_provider" msgid="6135073566140050702">"enregistrer de nouvelles connexions de télécommunication"</string>
- <string name="permdesc_register_call_provider" msgid="4201429251459068613">"Permettre à l\'application d\'enregistrer de nouvelles connexions de télécommunication"</string>
+ <string name="permdesc_register_call_provider" msgid="4201429251459068613">"Permettre à l\'appli d\'enregistrer de nouvelles connexions de télécommunication"</string>
<string name="permlab_connection_manager" msgid="3179365584691166915">"gérer les connexions de télécommunication"</string>
- <string name="permdesc_connection_manager" msgid="1426093604238937733">"Permettre à l\'application de gérer les connexions de télécommunication"</string>
+ <string name="permdesc_connection_manager" msgid="1426093604238937733">"Permettre à l\'appli de gérer les connexions de télécommunication"</string>
<string name="permlab_bind_incall_service" msgid="5990625112603493016">"interagir avec l\'écran d\'appel"</string>
- <string name="permdesc_bind_incall_service" msgid="4124917526967765162">"Permet à l\'application de contrôler quand et comment l\'écran d\'appel s\'affiche."</string>
+ <string name="permdesc_bind_incall_service" msgid="4124917526967765162">"Permet à l\'appli de contrôler quand et comment l\'écran d\'appel s\'affiche."</string>
<string name="permlab_bind_connection_service" msgid="5409268245525024736">"interagir avec les services de téléphonie"</string>
- <string name="permdesc_bind_connection_service" msgid="6261796725253264518">"Permet à l\'application d\'interagir avec les services de téléphonie afin de faire et de recevoir des appels."</string>
+ <string name="permdesc_bind_connection_service" msgid="6261796725253264518">"Permet à l\'appli d\'interagir avec les services de téléphonie afin de faire et de recevoir des appels."</string>
<string name="permlab_control_incall_experience" msgid="6436863486094352987">"fournir une expérience utilisateur pendant l\'appel"</string>
- <string name="permdesc_control_incall_experience" msgid="5896723643771737534">"Permet à l\'application de fournir une expérience utilisateur pendant l\'appel."</string>
+ <string name="permdesc_control_incall_experience" msgid="5896723643771737534">"Permet à l\'appli de fournir une expérience utilisateur pendant l\'appel."</string>
<string name="permlab_readNetworkUsageHistory" msgid="8470402862501573795">"lire l\'historique d\'utilisation de réseaux"</string>
- <string name="permdesc_readNetworkUsageHistory" msgid="1112962304941637102">"Permet à l\'application de lire l\'historique d\'utilisation de réseaux et d\'applications particuliers."</string>
+ <string name="permdesc_readNetworkUsageHistory" msgid="1112962304941637102">"Permet à l\'appli de lire l\'historique d\'utilisation de réseaux et d\'applis particuliers."</string>
<string name="permlab_manageNetworkPolicy" msgid="6872549423152175378">"gérer les politiques du réseau"</string>
- <string name="permdesc_manageNetworkPolicy" msgid="1865663268764673296">"Permet à l\'application de gérer les politiques du réseau et de définir celles propres à l\'application"</string>
+ <string name="permdesc_manageNetworkPolicy" msgid="1865663268764673296">"Permet à l\'appli de gérer les politiques du réseau et de définir celles propres à l\'appli"</string>
<string name="permlab_modifyNetworkAccounting" msgid="7448790834938749041">"modifier le système d\'analyse de l\'utilisation du réseau"</string>
- <string name="permdesc_modifyNetworkAccounting" msgid="5076042642247205390">"Permet à l\'application de modifier le système d\'analyse de l\'utilisation du réseau par les autres applications. Les applications standards ne doivent pas utiliser cette fonctionnalité."</string>
+ <string name="permdesc_modifyNetworkAccounting" msgid="5076042642247205390">"Permet à l\'appli de modifier le système d\'analyse de l\'utilisation du réseau par les autres applis. Les applis standards ne doivent pas utiliser cette fonctionnalité."</string>
<string name="permlab_accessNotifications" msgid="7130360248191984741">"accéder aux notifications"</string>
- <string name="permdesc_accessNotifications" msgid="761730149268789668">"Permet aux applications de récupérer, d\'examiner et d\'autoriser les notifications, y compris celles envoyées par d\'autres applications."</string>
+ <string name="permdesc_accessNotifications" msgid="761730149268789668">"Permet aux applis de récupérer, d\'examiner et d\'autoriser les notifications, y compris celles envoyées par d\'autres applis."</string>
<string name="permlab_bindNotificationListenerService" msgid="5848096702733262458">"s\'associer à l\'interface de niveau supérieur d\'un service d\'écoute des notifications"</string>
- <string name="permdesc_bindNotificationListenerService" msgid="4970553694467137126">"Permet à l\'application de s\'associer à l\'interface de niveau supérieur d\'un service d\'écoute des notifications. Ne devrait jamais être nécessaire pour les applications normales."</string>
+ <string name="permdesc_bindNotificationListenerService" msgid="4970553694467137126">"Permet à l\'appli de s\'associer à l\'interface de niveau supérieur d\'un service d\'écoute des notifications. Ne devrait jamais être nécessaire pour les applis normales."</string>
<string name="permlab_bindConditionProviderService" msgid="5245421224814878483">"s\'associer à un service de fournisseur de conditions"</string>
- <string name="permdesc_bindConditionProviderService" msgid="6106018791256120258">"Permet à l\'application de s\'associer à l\'interface de niveau supérieur d\'un service de fournisseur de conditions. Ne devrait pas être nécessaire pour les applications standards."</string>
+ <string name="permdesc_bindConditionProviderService" msgid="6106018791256120258">"Permet à l\'appli de s\'associer à l\'interface de niveau supérieur d\'un service de fournisseur de conditions. Ne devrait pas être nécessaire pour les applis standards."</string>
<string name="permlab_bindDreamService" msgid="4776175992848982706">"associer à un service de rêve"</string>
- <string name="permdesc_bindDreamService" msgid="9129615743300572973">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un service de rêve. Les applications standard ne devraient pas avoir recours à cette fonctionnalité."</string>
- <string name="permlab_invokeCarrierSetup" msgid="5098810760209818140">"faire appel à l\'application de configuration du fournisseur de services"</string>
- <string name="permdesc_invokeCarrierSetup" msgid="4790845896063237887">"Permet à l\'application autorisée de faire appel à l\'application de configuration fournie par le fournisseur de services. Cette fonctionnalité ne devrait pas être nécessaire pour les applications standards."</string>
+ <string name="permdesc_bindDreamService" msgid="9129615743300572973">"Permet à l\'appli autorisée de s\'associer à l\'interface de plus haut niveau d\'un service de rêve. Les applis standard ne devraient pas avoir recours à cette fonctionnalité."</string>
+ <string name="permlab_invokeCarrierSetup" msgid="5098810760209818140">"faire appel à l\'appli de configuration du fournisseur de services"</string>
+ <string name="permdesc_invokeCarrierSetup" msgid="4790845896063237887">"Permet à l\'appli autorisée de faire appel à l\'appli de configuration fournie par le fournisseur de services. Cette fonctionnalité ne devrait pas être nécessaire pour les applis standards."</string>
<string name="permlab_accessNetworkConditions" msgid="1270732533356286514">"détecter des observations sur les conditions du réseau"</string>
- <string name="permdesc_accessNetworkConditions" msgid="2959269186741956109">"Permet à une application de détecter les observations sur les conditions du réseau. Ne devrait jamais être nécessaire pour les applications standards."</string>
+ <string name="permdesc_accessNetworkConditions" msgid="2959269186741956109">"Permet à une appli de détecter les observations sur les conditions du réseau. Ne devrait jamais être nécessaire pour les applis standards."</string>
<string name="permlab_setInputCalibration" msgid="932069700285223434">"modifier le calibrage du périphérique d\'entrée"</string>
- <string name="permdesc_setInputCalibration" msgid="2937872391426631726">"Permet à l\'application de modifier les paramètres de calibrage de l\'écran tactile. Ne devrait jamais être nécessaire pour les applications standards."</string>
+ <string name="permdesc_setInputCalibration" msgid="2937872391426631726">"Permet à l\'appli de modifier les paramètres de calibrage de l\'écran tactile. Ne devrait jamais être nécessaire pour les applis standards."</string>
<string name="permlab_accessDrmCertificates" msgid="6473765454472436597">"accéder aux certificats GDN"</string>
- <string name="permdesc_accessDrmCertificates" msgid="6983139753493781941">"Permet à une application de fournir et d\'utiliser les certificats de GDN. Cela ne devrait jamais être nécessaire pour les applications normales."</string>
+ <string name="permdesc_accessDrmCertificates" msgid="6983139753493781941">"Permet à une appli de fournir et d\'utiliser les certificats de GDN. Cela ne devrait jamais être nécessaire pour les applis normales."</string>
<string name="permlab_handoverStatus" msgid="7620438488137057281">"recevoir des données sur l\'état du transfert Android Beam"</string>
- <string name="permdesc_handoverStatus" msgid="3842269451732571070">"Autoriser cette application à recevoir des données sur les transferts Android Beam en cours"</string>
+ <string name="permdesc_handoverStatus" msgid="3842269451732571070">"Autoriser cette appli à recevoir des données sur les transferts Android Beam en cours"</string>
<string name="permlab_removeDrmCertificates" msgid="710576248717404416">"supprimer des certificats GDN"</string>
- <string name="permdesc_removeDrmCertificates" msgid="4068445390318355716">"Permet à une application de supprimer les certificats GDN. Cela ne devrait jamais être nécessaire pour des applications normales."</string>
+ <string name="permdesc_removeDrmCertificates" msgid="4068445390318355716">"Permet à une appli de supprimer les certificats GDN. Cela ne devrait jamais être nécessaire pour des applis normales."</string>
<string name="permlab_bindCarrierMessagingService" msgid="3363450860593096967">"s\'associer à un service de messagerie d\'un fournisseur"</string>
- <string name="permdesc_bindCarrierMessagingService" msgid="6316457028173478345">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un service de messagerie d\'un fournisseur. Les applications standards ne devraient jamais avoir recours à cette fonctionnalité."</string>
+ <string name="permdesc_bindCarrierMessagingService" msgid="6316457028173478345">"Permet à l\'appli autorisée de s\'associer à l\'interface de plus haut niveau d\'un service de messagerie d\'un fournisseur. Les applis standards ne devraient jamais avoir recours à cette fonctionnalité."</string>
<string name="permlab_bindCarrierServices" msgid="2395596978626237474">"s\'associer aux services d\'un fournisseur"</string>
- <string name="permdesc_bindCarrierServices" msgid="9185614481967262900">"Permet à l\'application autorisée de s\'associer aux services d\'un fournisseur. Ne devrait pas être nécessaire pour les applications standards."</string>
+ <string name="permdesc_bindCarrierServices" msgid="9185614481967262900">"Permet à l\'appli autorisée de s\'associer aux services d\'un fournisseur. Ne devrait pas être nécessaire pour les applis standards."</string>
<string name="permlab_access_notification_policy" msgid="5524112842876975537">"accéder au mode Ne pas déranger"</string>
- <string name="permdesc_access_notification_policy" msgid="8538374112403845013">"Permet à l\'application de consulter et de modifier la configuration du mode Ne pas déranger."</string>
+ <string name="permdesc_access_notification_policy" msgid="8538374112403845013">"Permet à l\'appli de consulter et de modifier la configuration du mode Ne pas déranger."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"démarrer l\'affichage de l\'usage des autorisations"</string>
- <string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"Permet au détenteur de démarrer l\'usage des autorisations pour une application. Cette fonctionnalité ne devrait pas être nécessaire pour les applications standards."</string>
+ <string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"Permet au détenteur de démarrer l\'usage des autorisations pour une appli. Cette fonctionnalité ne devrait pas être nécessaire pour les applis standards."</string>
<string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"démarrer les décisions d\'autorisation de lecture"</string>
- <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"Permet au détenteur de démarrer l\'écran pour revoir les décisions d\'autorisation. Ne devrait pas être requis pour les applications standards."</string>
- <string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"démarrer l\'affichage des fonctionnalités de l\'application"</string>
- <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Permet au détenteur de commencer à afficher les renseignements sur les fonctionnalités d\'une application."</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"Permet au détenteur de démarrer l\'écran pour revoir les décisions d\'autorisation. Ne devrait pas être requis pour les applis standards."</string>
+ <string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"démarrer l\'affichage des fonctionnalités de l\'appli"</string>
+ <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Permet au détenteur de commencer à afficher les renseignements sur les fonctionnalités d\'une appli."</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"accéder aux données des capteurs à un taux d’échantillonnage élevé"</string>
- <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Permet à l’application d’échantillonner les données des capteurs à une fréquence supérieure à 200 Hz"</string>
- <string name="permlab_updatePackagesWithoutUserAction" msgid="3363272609642618551">"Mettre à jour l\'application sans intervention de l\'utilisateur"</string>
- <string name="permdesc_updatePackagesWithoutUserAction" msgid="4567739631260526366">"Permet à une application précédemment installée de se mettre à jour sans intervention de l\'utilisateur"</string>
- <string name="permlab_writeVerificationStateE2eeContactKeys" msgid="3990742344778360457">"mettre à jour les états des vérifications des clés de contact chiffrées de bout en bout qui appartiennent à d\'autres applications"</string>
- <string name="permdesc_writeVerificationStateE2eeContactKeys" msgid="8453156829747427041">"Autorise l\'application à mettre à jour les états des vérifications des clés de contact chiffrées de bout en bout qui appartiennent à d\'autres applications"</string>
+ <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Permet à l’appli d’échantillonner les données des capteurs à une fréquence supérieure à 200 Hz"</string>
+ <string name="permlab_updatePackagesWithoutUserAction" msgid="3363272609642618551">"Mettre à jour l\'appli sans intervention de l\'utilisateur"</string>
+ <string name="permdesc_updatePackagesWithoutUserAction" msgid="4567739631260526366">"Permet à une appli précédemment installée de se mettre à jour sans intervention de l\'utilisateur"</string>
+ <string name="permlab_writeVerificationStateE2eeContactKeys" msgid="3990742344778360457">"mettre à jour les états des vérifications des clés de contact chiffrées de bout en bout qui appartiennent à d\'autres applis"</string>
+ <string name="permdesc_writeVerificationStateE2eeContactKeys" msgid="8453156829747427041">"Autorise l\'appli à mettre à jour les états des vérifications des clés de contact chiffrées de bout en bout qui appartiennent à d\'autres applis"</string>
<string name="policylab_limitPassword" msgid="4851829918814422199">"Définir les règles du mot de passe"</string>
<string name="policydesc_limitPassword" msgid="4105491021115793793">"Gérer le nombre et le type de caractères autorisés dans les mots de passe et les NIP de verrouillage de l\'écran."</string>
<string name="policylab_watchLogin" msgid="7599669460083719504">"Gérer les tentatives de déverrouillage de l\'écran"</string>
@@ -866,7 +864,7 @@
<string name="policylab_expirePassword" msgid="6015404400532459169">"Déf. expir. m. passe verr. écr."</string>
<string name="policydesc_expirePassword" msgid="9136524319325960675">"Modifier la fréquence de modification du mot de passe, du NIP ou du schéma de verrouillage de l\'écran."</string>
<string name="policylab_encryptedStorage" msgid="9012936958126670110">"Définir cryptage du stockage"</string>
- <string name="policydesc_encryptedStorage" msgid="1102516950740375617">"Exiger le chiffrement des données d\'application stockées"</string>
+ <string name="policydesc_encryptedStorage" msgid="1102516950740375617">"Exiger le chiffrement des données d\'appli stockées"</string>
<string name="policylab_disableCamera" msgid="5749486347810162018">"Désactiver les appareils photo"</string>
<string name="policydesc_disableCamera" msgid="3204405908799676104">"Empêcher l\'utilisation de tous les appareils photos"</string>
<string name="policylab_disableKeyguardFeatures" msgid="5071855750149949741">"Désact. fonctions verr. écran"</string>
@@ -984,7 +982,7 @@
<string name="sipAddressTypeHome" msgid="5918441930656878367">"Domicile"</string>
<string name="sipAddressTypeWork" msgid="7873967986701216770">"Travail"</string>
<string name="sipAddressTypeOther" msgid="6317012577345187275">"Autre"</string>
- <string name="quick_contacts_not_available" msgid="1262709196045052223">"Aucune application permettant d\'afficher ce contact n\'a été trouvée."</string>
+ <string name="quick_contacts_not_available" msgid="1262709196045052223">"Aucune appli permettant d\'afficher ce contact n\'a été trouvée."</string>
<string name="keyguard_password_enter_pin_code" msgid="6401406801060956153">"Saisissez le NIP."</string>
<string name="keyguard_password_enter_puk_code" msgid="3112256684547584093">"Saisissez la clé PUK et le nouveau NIP."</string>
<string name="keyguard_password_enter_puk_prompt" msgid="2825313071899938305">"Clé PUK"</string>
@@ -1102,9 +1100,9 @@
<string name="js_dialog_before_unload" msgid="7213364985774778744">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nVoulez-vous vraiment quitter cette page?"</string>
<string name="autofill_window_title" msgid="4379134104008111961">"Remplissage automatique avec <xliff:g id="SERVICENAME">%1$s</xliff:g>"</string>
<string name="permlab_setAlarm" msgid="1158001610254173567">"définir une alarme"</string>
- <string name="permdesc_setAlarm" msgid="2185033720060109640">"Permet à l\'application de régler la sonnerie d\'une fonction de réveil installée sur votre appareil. Cette fonctionnalité n\'est pas compatible avec toutes les applications de réveils."</string>
+ <string name="permdesc_setAlarm" msgid="2185033720060109640">"Permet à l\'appli de régler la sonnerie d\'une fonction de réveil installée sur votre appareil. Cette fonctionnalité n\'est pas compatible avec toutes les applis de réveils."</string>
<string name="permlab_addVoicemail" msgid="4770245808840814471">"ajouter des messages vocaux"</string>
- <string name="permdesc_addVoicemail" msgid="5470312139820074324">"Permet à l\'application d\'ajouter des messages à votre messagerie vocale."</string>
+ <string name="permdesc_addVoicemail" msgid="5470312139820074324">"Permet à l\'appli d\'ajouter des messages à votre messagerie vocale."</string>
<string name="pasted_from_clipboard" msgid="7355790625710831847">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> a collé du contenu de votre presse-papiers"</string>
<string name="more_item_label" msgid="7419249600215749115">"Plus"</string>
<string name="prepend_shortcut_label" msgid="1743716737502867951">"Menu+"</string>
@@ -1201,7 +1199,7 @@
<string name="low_internal_storage_view_text" msgid="8172166728369697835">"Il est possible que certaines fonctionnalités du système ne soient pas opérationnelles."</string>
<string name="low_internal_storage_view_text_no_boot" msgid="7368968163411251788">"Espace de stockage insuffisant pour le système. Assurez-vous de disposer de 250 Mo d\'espace libre, puis redémarrez."</string>
<string name="app_running_notification_title" msgid="8985999749231486569">"<xliff:g id="APP_NAME">%1$s</xliff:g> en cours d\'exécution"</string>
- <string name="app_running_notification_text" msgid="5120815883400228566">"Touchez pour en savoir plus ou pour arrêter l\'application."</string>
+ <string name="app_running_notification_text" msgid="5120815883400228566">"Touchez pour en savoir plus ou pour arrêter l\'appli."</string>
<string name="ok" msgid="2646370155170753815">"OK"</string>
<string name="cancel" msgid="6908697720451760115">"Annuler"</string>
<string name="yes" msgid="9069828999585032361">"OK"</string>
@@ -1236,28 +1234,28 @@
<string name="whichSendToApplication" msgid="77101541959464018">"Envoyer avec"</string>
<string name="whichSendToApplicationNamed" msgid="3385686512014670003">"Envoyer avec %1$s"</string>
<string name="whichSendToApplicationLabel" msgid="3543240188816513303">"Envoyer"</string>
- <string name="whichHomeApplication" msgid="8276350727038396616">"Sélectionner une application pour l\'écran d\'accueil"</string>
+ <string name="whichHomeApplication" msgid="8276350727038396616">"Sélectionner une appli pour l\'écran d\'accueil"</string>
<string name="whichHomeApplicationNamed" msgid="5855990024847433794">"Utiliser %1$s comme écran d\'accueil"</string>
<string name="whichHomeApplicationLabel" msgid="8907334282202933959">"Enregistrer l\'image"</string>
<string name="whichImageCaptureApplication" msgid="2737413019463215284">"Enregistrer l\'image avec"</string>
<string name="whichImageCaptureApplicationNamed" msgid="8820702441847612202">"Enregistrer l\'image avec %1$s"</string>
<string name="whichImageCaptureApplicationLabel" msgid="6505433734824988277">"Enregistrer l\'image"</string>
- <string name="alwaysUse" msgid="3153558199076112903">"Utiliser cette application par défaut pour cette action"</string>
+ <string name="alwaysUse" msgid="3153558199076112903">"Utiliser cette appli par défaut pour cette action"</string>
<string name="use_a_different_app" msgid="4987790276170972776">"Utiliser une appli différente"</string>
- <string name="clearDefaultHintMsg" msgid="1325866337702524936">"Pour supprimer les valeurs par défaut, accédez à Paramètres système &gt; Applications &gt; Téléchargements."</string>
+ <string name="clearDefaultHintMsg" msgid="1325866337702524936">"Pour supprimer les valeurs par défaut, accédez à Paramètres système &gt; Applis &gt; Téléchargements."</string>
<string name="chooseActivity" msgid="8563390197659779956">"Sélectionnez une action"</string>
- <string name="chooseUsbActivity" msgid="2096269989990986612">"Sélectionnez une application pour le périphérique de stockage USB"</string>
- <string name="noApplications" msgid="1186909265235544019">"Aucune application ne peut effectuer cette action."</string>
+ <string name="chooseUsbActivity" msgid="2096269989990986612">"Sélectionnez une appli pour le périphérique de stockage USB"</string>
+ <string name="noApplications" msgid="1186909265235544019">"Aucune appli ne peut effectuer cette action."</string>
<string name="aerr_application" msgid="4090916809370389109">"<xliff:g id="APPLICATION">%1$s</xliff:g> a cessé de fonctionner"</string>
<string name="aerr_process" msgid="4268018696970966407">"<xliff:g id="PROCESS">%1$s</xliff:g> a cessé de fonctionner"</string>
<string name="aerr_application_repeated" msgid="7804378743218496566">"<xliff:g id="APPLICATION">%1$s</xliff:g> plante continuellement"</string>
<string name="aerr_process_repeated" msgid="1153152413537954974">"<xliff:g id="PROCESS">%1$s</xliff:g> plante continuellement"</string>
- <string name="aerr_restart" msgid="2789618625210505419">"Rouvrir l\'application"</string>
+ <string name="aerr_restart" msgid="2789618625210505419">"Rouvrir l\'appli"</string>
<string name="aerr_report" msgid="3095644466849299308">"Envoyer des commentaires"</string>
<string name="aerr_close" msgid="3398336821267021852">"Fermer"</string>
<string name="aerr_mute" msgid="2304972923480211376">"Désactiver jusqu\'au redémarrage de l\'appareil"</string>
<string name="aerr_wait" msgid="3198677780474548217">"Attendre"</string>
- <string name="aerr_close_app" msgid="8318883106083050970">"Fermer l\'application"</string>
+ <string name="aerr_close_app" msgid="8318883106083050970">"Fermer l\'appli"</string>
<string name="anr_title" msgid="7290329487067300120"></string>
<string name="anr_activity_application" msgid="8121716632960340680">"<xliff:g id="APPLICATION">%2$s</xliff:g> ne répond pas"</string>
<string name="anr_activity_process" msgid="3477362583767128667">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ne répond pas"</string>
@@ -1267,18 +1265,18 @@
<string name="report" msgid="2149194372340349521">"Signaler"</string>
<string name="wait" msgid="7765985809494033348">"Attendre"</string>
<string name="webpage_unresponsive" msgid="7850879412195273433">"La page ne répond pas.\n \nVoulez-vous la fermer?"</string>
- <string name="launch_warning_title" msgid="6725456009564953595">"Application redirigée"</string>
+ <string name="launch_warning_title" msgid="6725456009564953595">"Appli redirigée"</string>
<string name="launch_warning_replace" msgid="3073392976283203402">"<xliff:g id="APP_NAME">%1$s</xliff:g> est maintenant lancée."</string>
- <string name="launch_warning_original" msgid="3332206576800169626">"L\'application <xliff:g id="APP_NAME">%1$s</xliff:g> a été lancée initialement."</string>
+ <string name="launch_warning_original" msgid="3332206576800169626">"L\'appli <xliff:g id="APP_NAME">%1$s</xliff:g> a été lancée initialement."</string>
<string name="screen_compat_mode_scale" msgid="8627359598437527726">"Redimensionner"</string>
<string name="screen_compat_mode_show" msgid="5080361367584709857">"Toujours afficher"</string>
- <string name="screen_compat_mode_hint" msgid="4032272159093750908">"Réactivez ce mode en accédant à Paramètres système &gt; Applications &gt; Téléchargements"</string>
+ <string name="screen_compat_mode_hint" msgid="4032272159093750908">"Réactivez ce mode en accédant à Paramètres système &gt; Applis &gt; Téléchargements"</string>
<string name="unsupported_display_size_message" msgid="7265211375269394699">"<xliff:g id="APP_NAME">%1$s</xliff:g> n\'est pas compatible avec le paramètre de taille d\'affichage actuel et peut se comporter de manière inattendue."</string>
<string name="unsupported_display_size_show" msgid="980129850974919375">"Toujours afficher"</string>
- <string name="unsupported_compile_sdk_message" msgid="7326293500707890537">"<xliff:g id="APP_NAME">%1$s</xliff:g> a été conçue pour une version incompatible du système d\'exploitation Android et peut se comporter de manière inattendue. Il se peut qu\'une version mise à jour de l\'application soit proposée."</string>
+ <string name="unsupported_compile_sdk_message" msgid="7326293500707890537">"<xliff:g id="APP_NAME">%1$s</xliff:g> a été conçue pour une version incompatible du système d\'exploitation Android et peut se comporter de manière inattendue. Il se peut qu\'une version mise à jour de l\'appli soit proposée."</string>
<string name="unsupported_compile_sdk_show" msgid="1601210057960312248">"Toujours afficher"</string>
<string name="unsupported_compile_sdk_check_update" msgid="1103639989147664456">"Vérifier la présence de mises à jour"</string>
- <string name="smv_application" msgid="3775183542777792638">"L\'application <xliff:g id="APPLICATION">%1$s</xliff:g> (du processus <xliff:g id="PROCESS">%2$s</xliff:g>) a enfreint ses propres règles du mode strict."</string>
+ <string name="smv_application" msgid="3775183542777792638">"L\'appli <xliff:g id="APPLICATION">%1$s</xliff:g> (du processus <xliff:g id="PROCESS">%2$s</xliff:g>) a enfreint ses propres règles du mode strict."</string>
<string name="smv_process" msgid="1398801497130695446">"Le processus <xliff:g id="PROCESS">%1$s</xliff:g> a enfreint ses propres règles du mode strict."</string>
<string name="android_upgrading_title" product="default" msgid="7279077384220829683">"Mise à jour du téléphone en cours…"</string>
<string name="android_upgrading_title" product="tablet" msgid="4268417249079938805">"Mise à jour de la tablette en cours…"</string>
@@ -1290,7 +1288,7 @@
<string name="android_upgrading_notification_title" product="default" msgid="3509927005342279257">"Finalisation de la m. à j. syst. en cours…"</string>
<string name="app_upgrading_toast" msgid="1016267296049455585">"Mise à niveau de <xliff:g id="APPLICATION">%1$s</xliff:g> en cours…"</string>
<string name="android_preparing_apk" msgid="589736917792300956">"Préparation de <xliff:g id="APPNAME">%1$s</xliff:g> en cours…"</string>
- <string name="android_upgrading_starting_apps" msgid="6206161195076057075">"Lancement des applications…"</string>
+ <string name="android_upgrading_starting_apps" msgid="6206161195076057075">"Lancement des applis…"</string>
<string name="android_upgrading_complete" msgid="409800058018374746">"Finalisation de la mise à jour."</string>
<string name="fp_power_button_enrollment_message" msgid="5648173517663246140">"Vous avez appuyé sur le l\'interrupteur – cette action éteint habituellement l\'écran.\n\nEssayez de toucher légèrement pendant la configuration de votre empreinte digitale."</string>
<string name="fp_power_button_enrollment_title" msgid="6976841690455338563">"Pour terminer, éteignez l\'écran"</string>
@@ -1310,9 +1308,9 @@
<string name="dump_heap_ready_notification" msgid="2302452262927390268">"L\'empreinte de mémoire <xliff:g id="PROC">%1$s</xliff:g> est prête"</string>
<string name="dump_heap_notification_detail" msgid="8431586843001054050">"L\'empreinte de mémoire a été recueillie. Touchez ici pour la partager."</string>
<string name="dump_heap_title" msgid="4367128917229233901">"Partager l\'empreinte de mémoire?"</string>
- <string name="dump_heap_text" msgid="1692649033835719336">"Le processus <xliff:g id="PROC">%1$s</xliff:g> a dépassé sa limite de mémoire de <xliff:g id="SIZE">%2$s</xliff:g>. Vous pouvez partager son empreinte de mémoire avec son développeur. Attention : Cette empreinte peut contenir certains de vos renseignements personnels auxquels l\'application a accès."</string>
+ <string name="dump_heap_text" msgid="1692649033835719336">"Le processus <xliff:g id="PROC">%1$s</xliff:g> a dépassé sa limite de mémoire de <xliff:g id="SIZE">%2$s</xliff:g>. Vous pouvez partager son empreinte de mémoire avec son développeur. Attention : Cette empreinte peut contenir certains de vos renseignements personnels auxquels l\'appli a accès."</string>
<string name="dump_heap_system_text" msgid="6805155514925350849">"Le processus <xliff:g id="PROC">%1$s</xliff:g> a dépassé sa limite de mémoire de <xliff:g id="SIZE">%2$s</xliff:g>. Vous pouvez partager son empreinte de mémoire. Attention : Cette empreinte peut contenir des renseignements personnels auxquels le processus a accès, y compris du texte que vous avez entré."</string>
- <string name="dump_heap_ready_text" msgid="5849618132123045516">"Une empreinte de mémoire du processus lié à l\'application <xliff:g id="PROC">%1$s</xliff:g> peut être partagée. Attention : Cette empreinte peut contenir des renseignements personnels auxquels le processus a accès, y compris du texte que vous avez entré."</string>
+ <string name="dump_heap_ready_text" msgid="5849618132123045516">"Une empreinte de mémoire du processus lié à l\'appli <xliff:g id="PROC">%1$s</xliff:g> peut être partagée. Attention : Cette empreinte peut contenir des renseignements personnels auxquels le processus a accès, y compris du texte que vous avez entré."</string>
<string name="sendText" msgid="493003724401350724">"Sélectionner une action pour le texte"</string>
<string name="volume_ringtone" msgid="134784084629229029">"Volume de la sonnerie"</string>
<string name="volume_music" msgid="7727274216734955095">"Volume du contenu multimédia"</string>
@@ -1361,7 +1359,7 @@
<string name="decline" msgid="6490507610282145874">"Refuser"</string>
<string name="select_character" msgid="3352797107930786979">"Insérer un caractère"</string>
<string name="sms_control_title" msgid="4748684259903148341">"Envoi de messages SMS"</string>
- <string name="sms_control_message" msgid="6574313876316388239">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; envoie un grand nombre de SMS. Autorisez-vous cette application à poursuivre l\'envoi des messages?"</string>
+ <string name="sms_control_message" msgid="6574313876316388239">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; envoie un grand nombre de SMS. Autorisez-vous cette appli à poursuivre l\'envoi des messages?"</string>
<string name="sms_control_yes" msgid="4858845109269524622">"Autoriser"</string>
<string name="sms_control_no" msgid="4845717880040355570">"Refuser"</string>
<string name="sms_short_code_confirm_message" msgid="1385416688897538724">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; souhaite envoyer un message à &lt;b&gt;<xliff:g id="DEST_ADDRESS">%2$s</xliff:g>&lt;/b&gt;."</string>
@@ -1370,7 +1368,7 @@
<string name="sms_short_code_confirm_allow" msgid="920477594325526691">"Envoyer"</string>
<string name="sms_short_code_confirm_deny" msgid="1356917469323768230">"Annuler"</string>
<string name="sms_short_code_remember_choice" msgid="1374526438647744862">"Mémoriser mon choix"</string>
- <string name="sms_short_code_remember_undo_instruction" msgid="2620984439143080410">"Pour modifier : Paramètres &gt; Applications"</string>
+ <string name="sms_short_code_remember_undo_instruction" msgid="2620984439143080410">"Pour modifier : Paramètres &gt; Applis"</string>
<string name="sms_short_code_confirm_always_allow" msgid="2223014893129755950">"Toujours autoriser"</string>
<string name="sms_short_code_confirm_never_allow" msgid="2688828813521652079">"Ne jamais autoriser"</string>
<string name="sim_removed_title" msgid="1349026474932481037">"Carte SIM retirée"</string>
@@ -1380,9 +1378,9 @@
<string name="sim_added_message" msgid="6602906609509958680">"Redémarrez votre appareil pour accéder au réseau mobile."</string>
<string name="sim_restart_button" msgid="8481803851341190038">"Redémarrer"</string>
<string name="install_carrier_app_notification_title" msgid="5712723402213090102">"Activer le service cellulaire"</string>
- <string name="install_carrier_app_notification_text" msgid="2781317581274192728">"Téléchargez l\'application du fournisseur de services pour activer votre nouvelle carte SIM"</string>
- <string name="install_carrier_app_notification_text_app_name" msgid="4086877327264106484">"Téléchargez l\'application de <xliff:g id="APP_NAME">%1$s</xliff:g> pour activer votre nouvelle carte SIM"</string>
- <string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Télécharger l\'application"</string>
+ <string name="install_carrier_app_notification_text" msgid="2781317581274192728">"Téléchargez l\'appli du fournisseur de services pour activer votre nouvelle carte SIM"</string>
+ <string name="install_carrier_app_notification_text_app_name" msgid="4086877327264106484">"Téléchargez l\'appli de <xliff:g id="APP_NAME">%1$s</xliff:g> pour activer votre nouvelle carte SIM"</string>
+ <string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Télécharger l\'appli"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"Nouvelle carte SIM insérée"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"Touchez ici pour effectuer la configuration"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"Définir l\'heure"</string>
@@ -1429,7 +1427,7 @@
<string name="taking_remote_bugreport_notification_title" msgid="1582531382166919850">"Création d\'un rapport de bogue en cours..."</string>
<string name="share_remote_bugreport_notification_title" msgid="6708897723753334999">"Partager le rapport de bogue?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="3077385149217638550">"Partage du rapport de bogue en cours..."</string>
- <string name="share_remote_bugreport_notification_message_finished" msgid="7325635795739260135">"Votre administrateur a demandé un rapport de bogue pour l\'aider à dépanner cet appareil. Les applications et les données peuvent être partagées."</string>
+ <string name="share_remote_bugreport_notification_message_finished" msgid="7325635795739260135">"Votre administrateur a demandé un rapport de bogue pour l\'aider à dépanner cet appareil. Les applis et les données peuvent être partagées."</string>
<string name="share_remote_bugreport_action" msgid="7630880678785123682">"PARTAGER"</string>
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"REFUSER"</string>
<string name="select_input_method" msgid="3971267998568587025">"Sélectionnez le mode de saisie"</string>
@@ -1441,7 +1439,7 @@
<string name="fast_scroll_alphabet" msgid="8854435958703888376">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="2529539945421557329">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="alert_windows_notification_channel_group_name" msgid="6063891141815714246">"Afficher par-dessus les autres applis"</string>
- <string name="alert_windows_notification_channel_name" msgid="3437528564303192620">"<xliff:g id="NAME">%s</xliff:g> affiche du contenu par-dessus d\'autres applications"</string>
+ <string name="alert_windows_notification_channel_name" msgid="3437528564303192620">"<xliff:g id="NAME">%s</xliff:g> affiche du contenu par-dessus d\'autres applis"</string>
<string name="alert_windows_notification_title" msgid="6331662751095228536">"<xliff:g id="NAME">%s</xliff:g> aff. contenu par-dessus applis"</string>
<string name="alert_windows_notification_message" msgid="6538171456970725333">"Si vous ne voulez pas que <xliff:g id="NAME">%s</xliff:g> utilise cette fonctionnalités, touchez l\'écran pour ouvrir les paramètres, puis désactivez-la."</string>
<string name="alert_windows_notification_turn_off_action" msgid="7805857234839123780">"Désactiver"</string>
@@ -1496,17 +1494,17 @@
<string name="ext_media_status_missing" msgid="6520746443048867314">"Non insérée"</string>
<string name="activity_list_empty" msgid="4219430010716034252">"Aucune activité correspondante trouvée."</string>
<string name="permlab_route_media_output" msgid="8048124531439513118">"diriger la sortie multimédia"</string>
- <string name="permdesc_route_media_output" msgid="1759683269387729675">"Permet à une application de diriger la sortie multimédia vers d\'autres appareils externes."</string>
+ <string name="permdesc_route_media_output" msgid="1759683269387729675">"Permet à une appli de diriger la sortie multimédia vers d\'autres appareils externes."</string>
<string name="permlab_readInstallSessions" msgid="7279049337895583621">"accéder aux sessions d\'installation"</string>
- <string name="permdesc_readInstallSessions" msgid="4012608316610763473">"Permet à une application d\'accéder aux sessions d\'installation. Cela lui permet de consulter les détails relatifs à l\'installation des paquets actifs."</string>
+ <string name="permdesc_readInstallSessions" msgid="4012608316610763473">"Permet à une appli d\'accéder aux sessions d\'installation. Cela lui permet de consulter les détails relatifs à l\'installation des paquets actifs."</string>
<string name="permlab_requestInstallPackages" msgid="7600020863445351154">"demander l\'installation de paquets"</string>
- <string name="permdesc_requestInstallPackages" msgid="3969369278325313067">"Permet à une application de demander l\'installation de paquets."</string>
+ <string name="permdesc_requestInstallPackages" msgid="3969369278325313067">"Permet à une appli de demander l\'installation de paquets."</string>
<string name="permlab_requestDeletePackages" msgid="2541172829260106795">"demander la suppression de paquets"</string>
- <string name="permdesc_requestDeletePackages" msgid="6133633516423860381">"Permet à une application de demander la suppression de paquets."</string>
+ <string name="permdesc_requestDeletePackages" msgid="6133633516423860381">"Permet à une appli de demander la suppression de paquets."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="7646611326036631439">"demander d\'ignorer les optimisations de la pile"</string>
- <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Permet à une application de demander la permission d\'ignorer les optimisations de la pile."</string>
+ <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Permet à une appli de demander la permission d\'ignorer les optimisations de la pile."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"envoyer une requête à propos de tous les paquets"</string>
- <string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Permet à une application de voir tous les paquets installés."</string>
+ <string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Permet à une appli de voir tous les paquets installés."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Appuyer deux fois pour régler le zoom"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"Impossible d\'ajouter le widget."</string>
<string name="ime_action_go" msgid="5536744546326495436">"Aller"</string>
@@ -1518,7 +1516,7 @@
<string name="ime_action_default" msgid="8265027027659800121">"Exécuter"</string>
<string name="dial_number_using" msgid="6060769078933953531">"Composer le numéro\nen utilisant <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="create_contact_using" msgid="6200708808003692594">"Ajouter un contact\nen utilisant <xliff:g id="NUMBER">%s</xliff:g>"</string>
- <string name="grant_credentials_permission_message_header" msgid="5365733888842570481">"Les applications suivantes demandent l\'autorisation d\'accéder à votre compte à partir de maintenant."</string>
+ <string name="grant_credentials_permission_message_header" msgid="5365733888842570481">"Les applis suivantes demandent l\'autorisation d\'accéder à votre compte à partir de maintenant."</string>
<string name="grant_credentials_permission_message_footer" msgid="1886710210516246461">"Voulez-vous autoriser cette demande?"</string>
<string name="grant_permissions_header_text" msgid="3420736827804657201">"Demande d\'accès"</string>
<string name="allow" msgid="6195617008611933762">"Autoriser"</string>
@@ -1526,8 +1524,8 @@
<string name="permission_request_notification_title" msgid="1810025922441048273">"Autorisation demandée"</string>
<string name="permission_request_notification_with_subtitle" msgid="3743417870360129298">"Autorisation demandée\npour le compte \"<xliff:g id="ACCOUNT">%s</xliff:g>\""</string>
<string name="permission_request_notification_for_app_with_subtitle" msgid="1298704005732851350">"Autorisation demandée par <xliff:g id="APP">%1$s</xliff:g>\npour le compte <xliff:g id="ACCOUNT">%2$s</xliff:g>."</string>
- <string name="forward_intent_to_owner" msgid="4620359037192871015">"Vous utilisez cette application en dehors de votre profil professionnel"</string>
- <string name="forward_intent_to_work" msgid="3620262405636021151">"Vous utilisez cette application dans votre profil professionnel"</string>
+ <string name="forward_intent_to_owner" msgid="4620359037192871015">"Vous utilisez cette appli en dehors de votre profil professionnel"</string>
+ <string name="forward_intent_to_work" msgid="3620262405636021151">"Vous utilisez cette appli dans votre profil professionnel"</string>
<string name="input_method_binding_label" msgid="1166731601721983656">"Mode de saisie"</string>
<string name="sync_binding_label" msgid="469249309424662147">"Synchroniser"</string>
<string name="accessibility_binding_label" msgid="1974602776545801715">"Accessibilité"</string>
@@ -1550,8 +1548,8 @@
<string name="no_file_chosen" msgid="4146295695162318057">"Aucun fichier sélectionné"</string>
<string name="reset" msgid="3865826612628171429">"Réinitialiser"</string>
<string name="submit" msgid="862795280643405865">"Envoyer"</string>
- <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"L\'application de conduite est en cours d\'exécution"</string>
- <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Touchez pour quitter l\'application de conduite."</string>
+ <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"L\'appli de conduite est en cours d\'exécution"</string>
+ <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Touchez pour quitter l\'appli de conduite."</string>
<string name="back_button_label" msgid="4078224038025043387">"Précédent"</string>
<string name="next_button_label" msgid="6040209156399907780">"Suivante"</string>
<string name="skip_button_label" msgid="3566599811326688389">"Ignorer"</string>
@@ -1603,8 +1601,8 @@
<string name="keyboardview_keycode_mode_change" msgid="2743735349997999020">"Changement de mode"</string>
<string name="keyboardview_keycode_shift" msgid="3026509237043975573">"Maj"</string>
<string name="keyboardview_keycode_enter" msgid="168054869339091055">"Entrée"</string>
- <string name="activitychooserview_choose_application" msgid="3500574466367891463">"Sélectionnez une application"</string>
- <string name="activitychooserview_choose_application_error" msgid="6937782107559241734">"Impossible de lancer l\'application <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
+ <string name="activitychooserview_choose_application" msgid="3500574466367891463">"Sélectionnez une appli"</string>
+ <string name="activitychooserview_choose_application_error" msgid="6937782107559241734">"Impossible de lancer l\'appli <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="shareactionprovider_share_with" msgid="2753089758467748982">"Partagez avec"</string>
<string name="shareactionprovider_share_with_application" msgid="4902832247173666973">"Partager avec <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="content_description_sliding_handle" msgid="982510275422590757">"Poignée coulissante. Appuyez de manière prolongée."</string>
@@ -1632,7 +1630,7 @@
<string name="data_usage_restricted_title" msgid="126711424380051268">"Données en arrière-plan limitées"</string>
<string name="data_usage_restricted_body" msgid="5338694433686077733">"Touchez pour suppr. restriction."</string>
<string name="data_usage_rapid_title" msgid="2950192123248740375">"Utilis. élevée des données cell."</string>
- <string name="data_usage_rapid_body" msgid="3886676853263693432">"Vos applications ont utilisé plus de données que d\'habitude"</string>
+ <string name="data_usage_rapid_body" msgid="3886676853263693432">"Vos applis ont utilisé plus de données que d\'habitude"</string>
<string name="data_usage_rapid_app_body" msgid="5425779218506513861">"<xliff:g id="APP">%s</xliff:g> a utilisé plus de données que d\'habitude"</string>
<string name="ssl_certificate" msgid="5690020361307261997">"Certificat de sécurité"</string>
<string name="ssl_certificate_is_valid" msgid="7293675884598527081">"Ce certificat est valide."</string>
@@ -1737,15 +1735,15 @@
<string name="accessibility_shortcut_menu_item_status_on" msgid="6608392117189732543">"ACTIVÉ"</string>
<string name="accessibility_shortcut_menu_item_status_off" msgid="5531598275559472393">"DÉSACTIVÉ"</string>
<string name="accessibility_enable_service_title" msgid="3931558336268541484">"Permettre à <xliff:g id="SERVICE">%1$s</xliff:g> de contrôler complètement votre appareil?"</string>
- <string name="accessibility_service_warning_description" msgid="291674995220940133">"Le contrôle total convient aux applications qui répondent à vos besoins d\'accessibilité. Il ne convient pas à la plupart des applications."</string>
+ <string name="accessibility_service_warning_description" msgid="291674995220940133">"Le contrôle total convient aux applis qui répondent à vos besoins d\'accessibilité. Il ne convient pas à la plupart des applis."</string>
<string name="accessibility_service_screen_control_title" msgid="190017412626919776">"Afficher et contrôler l\'écran"</string>
- <string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"Cette fonctionnalité peut lire tout le contenu à l\'écran et afficher du contenu par-dessus d\'autres applications."</string>
+ <string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"Cette fonctionnalité peut lire tout le contenu à l\'écran et afficher du contenu par-dessus d\'autres applis."</string>
<string name="accessibility_service_action_perform_title" msgid="779670378951658160">"Afficher et effectuer des actions"</string>
- <string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"Cette fonctionnalité peut faire le suivi de vos interactions avec une application ou un capteur matériel et interagir avec des applications en votre nom."</string>
+ <string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"Cette fonctionnalité peut faire le suivi de vos interactions avec une appli ou un capteur matériel et interagir avec des applis en votre nom."</string>
<string name="accessibility_dialog_button_allow" msgid="2092558122987144530">"Autoriser"</string>
<string name="accessibility_dialog_button_deny" msgid="4129575637812472671">"Refuser"</string>
<string name="accessibility_dialog_button_uninstall" msgid="2952465517671708108">"Désinstaller"</string>
- <string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"Une application masque la demande d\'autorisation de sorte que votre réponse ne peut pas être vérifiée."</string>
+ <string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"Une appli masque la demande d\'autorisation de sorte que votre réponse ne peut pas être vérifiée."</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Toucher une fonctionnalité pour commencer à l\'utiliser :"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Choisir les fonctionnalités à utiliser à l\'aide du bouton d\'accessibilité"</string>
<string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Choisir les fonctionnalités à utiliser avec le raccourci des touches de volume"</string>
@@ -1768,12 +1766,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"La fonctionnalité s\'ouvrira la prochaine fois que vous toucherez le bouton d\'accessibilité"</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"La fonctionnalité s\'ouvrira la prochaine fois que vous utiliserez ce raccourci. Balayez l\'écran du bas vers le haut avec deux doigts et relâchez rapidement."</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"La fonctionnalité s\'ouvrira la prochaine fois que vous utiliserez ce raccourci. Balayez l\'écran du bas vers le haut avec trois doigts et relâchez rapidement."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Agrandissement"</string>
<string name="user_switched" msgid="7249833311585228097">"Utilisateur actuel : <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="user_switching_message" msgid="1912993630661332336">"Passage au profil : <xliff:g id="NAME">%1$s</xliff:g> en cours…"</string>
@@ -1782,7 +1777,7 @@
<string name="guest_name" msgid="8502103277839834324">"Invité"</string>
<string name="error_message_title" msgid="4082495589294631966">"Erreur"</string>
<string name="error_message_change_not_allowed" msgid="843159705042381454">"Cette modification n\'est pas autorisée par votre administrateur"</string>
- <string name="app_not_found" msgid="3429506115332341800">"Aucune application trouvée pour gérer cette action."</string>
+ <string name="app_not_found" msgid="3429506115332341800">"Aucune appli trouvée pour gérer cette action."</string>
<string name="revoke" msgid="5526857743819590458">"Révoquer"</string>
<string name="mediasize_iso_a0" msgid="7039061159929977973">"ISO A0"</string>
<string name="mediasize_iso_a1" msgid="4063589931031977223">"ISO A1"</string>
@@ -1995,7 +1990,7 @@
<string name="recs_notification_channel_label" msgid="4945985121418684297">"Recommandations"</string>
<string name="importance_from_user" msgid="2782756722448800447">"Vous définissez l\'importance de ces notifications."</string>
<string name="importance_from_person" msgid="4235804979664465383">"Ces notifications sont importantes en raison des participants."</string>
- <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Notification d\'application personnalisée"</string>
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Notification d\'appli personnalisée"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Autoriser <xliff:g id="APP">%1$s</xliff:g> à créer un utilisateur <xliff:g id="ACCOUNT">%2$s</xliff:g>? (Un utilisateur est déjà associé à ce compte)"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Autoriser <xliff:g id="APP">%1$s</xliff:g> à créer un profil d\'utilisateur avec le compte <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="supervised_user_creation_label" msgid="6884904353827427515">"Ajouter un utilisateur supervisé"</string>
@@ -2009,17 +2004,17 @@
<string name="language_picker_section_all" msgid="1985809075777564284">"Toutes les langues"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"Toutes les régions"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"Rechercher"</string>
- <string name="app_suspended_title" msgid="888873445010322650">"L\'application n\'est pas accessible"</string>
- <string name="app_suspended_default_message" msgid="6451215678552004172">"L\'application <xliff:g id="APP_NAME_0">%1$s</xliff:g> n\'est pas accessible pour le moment. Ceci est géré par <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
+ <string name="app_suspended_title" msgid="888873445010322650">"L\'appli n\'est pas accessible"</string>
+ <string name="app_suspended_default_message" msgid="6451215678552004172">"L\'appli <xliff:g id="APP_NAME_0">%1$s</xliff:g> n\'est pas accessible pour le moment. Ceci est géré par <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"En savoir plus"</string>
- <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Réactiver l\'application"</string>
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Réactiver l\'appli"</string>
<string name="work_mode_off_title" msgid="6367463960165135829">"Réactiver les applis pros?"</string>
<string name="work_mode_turn_on" msgid="5316648862401307800">"Réactiver"</string>
<string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Urgence"</string>
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Config. Verrouillage d\'écran"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Config. Verrouillage d\'écran"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Configurez verrouillage de l\'écran pour utiliser Espace privé"</string>
- <string name="app_blocked_title" msgid="7353262160455028160">"L\'application n\'est pas accessible"</string>
+ <string name="app_blocked_title" msgid="7353262160455028160">"L\'appli n\'est pas accessible"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> n\'est pas accessible pour le moment."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> non accessible"</string>
<string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"La demande d\'autorisation a été supprimée."</string>
@@ -2033,20 +2028,20 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Impossible d\'accéder à ce contenu sur votre <xliff:g id="DEVICE">%1$s</xliff:g> pour le moment. Essayez sur votre appareil Android TV à la place."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Impossible d\'accéder à ce contenu sur votre <xliff:g id="DEVICE">%1$s</xliff:g> pour le moment. Essayez sur votre tablette à la place."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Impossible d\'accéder à ce contenu sur votre <xliff:g id="DEVICE">%1$s</xliff:g> pour le moment. Essayez sur votre téléphone à la place."</string>
- <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"Cette application demande des autorisations supplémentaires, mais les autorisations ne peuvent pas être accordées lors d\'une session de diffusion en continu. Accordez l\'autorisation sur votre appareil Android TV d\'abord."</string>
- <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"Cette application demande des autorisations supplémentaires, mais les autorisations ne peuvent pas être accordées lors d\'une session de diffusion en continu. Accordez l\'autorisation sur votre tablette d\'abord."</string>
- <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"Cette application demande des autorisations supplémentaires, mais les autorisations ne peuvent pas être accordées lors d\'une session de diffusion en continu. Accordez l\'autorisation sur votre téléphone d\'abord."</string>
- <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Cette application demande une sécurité supplémentaire. Essayez sur votre appareil Android TV à la place."</string>
- <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Cette application demande une sécurité supplémentaire. Essayez sur votre tablette à la place."</string>
- <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Cette application demande une sécurité supplémentaire. Essayez sur votre téléphone à la place."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"Cette appli demande des autorisations supplémentaires, mais les autorisations ne peuvent pas être accordées lors d\'une session de diffusion en continu. Accordez l\'autorisation sur votre appareil Android TV d\'abord."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"Cette appli demande des autorisations supplémentaires, mais les autorisations ne peuvent pas être accordées lors d\'une session de diffusion en continu. Accordez l\'autorisation sur votre tablette d\'abord."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"Cette appli demande des autorisations supplémentaires, mais les autorisations ne peuvent pas être accordées lors d\'une session de diffusion en continu. Accordez l\'autorisation sur votre téléphone d\'abord."</string>
+ <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Cette appli demande une sécurité supplémentaire. Essayez sur votre appareil Android TV à la place."</string>
+ <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Cette appli demande une sécurité supplémentaire. Essayez sur votre tablette à la place."</string>
+ <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Cette appli demande une sécurité supplémentaire. Essayez sur votre téléphone à la place."</string>
<string name="app_streaming_blocked_message_for_settings_dialog" product="tv" msgid="820334666354451145">"Impossible d\'accéder à ce contenu sur votre <xliff:g id="DEVICE">%1$s</xliff:g>. Essayez sur votre appareil Android TV à la place."</string>
<string name="app_streaming_blocked_message_for_settings_dialog" product="tablet" msgid="3286849551133045896">"Impossible d\'accéder à ce contenu sur votre <xliff:g id="DEVICE">%1$s</xliff:g>. Essayez sur votre tablette à la place."</string>
<string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"Impossible d\'accéder à ce contenu sur votre <xliff:g id="DEVICE">%1$s</xliff:g>. Essayez sur votre téléphone à la place."</string>
- <string name="deprecated_target_sdk_message" msgid="5246906284426844596">"Cette application a été conçue pour une ancienne version d\'Android. Elle pourrait ne pas fonctionner correctement, et ne comprend pas les dernières protections des données confidentielles et de sécurité. Vérifiez s\'il existe une mise à jour ou contactez le développeur de l\'application."</string>
+ <string name="deprecated_target_sdk_message" msgid="5246906284426844596">"Cette appli a été conçue pour une ancienne version d\'Android. Elle pourrait ne pas fonctionner correctement, et ne comprend pas les dernières protections des données confidentielles et de sécurité. Vérifiez s\'il existe une mise à jour ou contactez le développeur de l\'appli."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Vérifier la présence de mises à jour"</string>
- <string name="deprecated_abi_message" msgid="6820548011196218091">"Cette application n\'est pas compatible avec la dernière version d\'Android. Vérifiez s\'il existe une mise à jour ou communiquez avec le développeur de l\'application."</string>
+ <string name="deprecated_abi_message" msgid="6820548011196218091">"Cette appli n\'est pas compatible avec la dernière version d\'Android. Vérifiez s\'il existe une mise à jour ou communiquez avec le développeur de l\'appli."</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Vous avez de nouveaux messages"</string>
- <string name="new_sms_notification_content" msgid="3197949934153460639">"Ouvrez l\'application de messagerie texte pour l\'afficher"</string>
+ <string name="new_sms_notification_content" msgid="3197949934153460639">"Ouvrez l\'appli de messagerie texte pour l\'afficher"</string>
<string name="profile_encrypted_title" msgid="9001208667521266472">"Des fonctionnalités sont limitées"</string>
<string name="profile_encrypted_detail" msgid="5279730442756849055">"Profil professionnel verrouillé"</string>
<string name="profile_encrypted_message" msgid="1128512616293157802">"Touch. pr déver. profil profess."</string>
@@ -2056,7 +2051,7 @@
<string name="pin_specific_target" msgid="7824671240625957415">"Épingler <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="unpin_target" msgid="3963318576590204447">"Annuler l\'épinglage"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"Annuler l\'épinglage de <xliff:g id="LABEL">%1$s</xliff:g>"</string>
- <string name="app_info" msgid="6113278084877079851">"Détails de l\'application"</string>
+ <string name="app_info" msgid="6113278084877079851">"Détails de l\'appli"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"Démarrage de la démonstration en cours…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"Réinitialisation de l\'appareil en cours…"</string>
@@ -2124,14 +2119,14 @@
<string name="mmcc_illegal_me_msim_template" msgid="4802735138861422802">"La carte SIM <xliff:g id="SIMNUMBER">%d</xliff:g> n\'est pas autorisée"</string>
<string name="popup_window_default_title" msgid="6907717596694826919">"Fenêtre contextuelle"</string>
<string name="slice_more_content" msgid="3377367737876888459">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
- <string name="shortcut_restored_on_lower_version" msgid="9206301954024286063">"La version de l\'application a été rétrogradée ou n\'est pas compatible avec ce raccourci"</string>
- <string name="shortcut_restore_not_supported" msgid="4763198938588468400">"Impossible de restaurer le raccourci, car l\'application ne prend pas en charge la sauvegarde et la restauration"</string>
- <string name="shortcut_restore_signature_mismatch" msgid="579345304221605479">"Impossible de restaurer le raccourci en raison d\'une erreur de correspondance des signature d\'applications"</string>
+ <string name="shortcut_restored_on_lower_version" msgid="9206301954024286063">"La version de l\'appli a été rétrogradée ou n\'est pas compatible avec ce raccourci"</string>
+ <string name="shortcut_restore_not_supported" msgid="4763198938588468400">"Impossible de restaurer le raccourci, car l\'appli ne prend pas en charge la sauvegarde et la restauration"</string>
+ <string name="shortcut_restore_signature_mismatch" msgid="579345304221605479">"Impossible de restaurer le raccourci en raison d\'une erreur de correspondance des signature d\'applis"</string>
<string name="shortcut_restore_unknown_issue" msgid="2478146134395982154">"Impossible de restaurer le raccourci"</string>
<string name="shortcut_disabled_reason_unknown" msgid="753074793553599166">"Le raccourci est désactivé"</string>
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"DÉSINSTALLER"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"OUVRIR QUAND MÊME"</string>
- <string name="harmful_app_warning_title" msgid="8794823880881113856">"Une application nuisible a été détectée"</string>
+ <string name="harmful_app_warning_title" msgid="8794823880881113856">"Une appli nuisible a été détectée"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> souhaite afficher <xliff:g id="APP_2">%2$s</xliff:g> tranches"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Modifier"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Les appels et les notifications vibreront"</string>
@@ -2143,14 +2138,14 @@
<string name="zen_upgrade_notification_title" msgid="8198167698095298717">"Les paramètres du mode Ne pas déranger ont changé"</string>
<string name="zen_upgrade_notification_content" msgid="5228458567180124005">"Touchez l\'écran pour vérifier ce qui est bloqué."</string>
<string name="review_notification_settings_title" msgid="5102557424459810820">"Examiner les paramètres de notification"</string>
- <string name="review_notification_settings_text" msgid="5916244866751849279">"À partir d\'Android 13, les applications que vous installez ont besoin de votre autorisation pour envoyer des notifications. Touchez pour modifier cette autorisation pour les applications existantes."</string>
+ <string name="review_notification_settings_text" msgid="5916244866751849279">"À partir d\'Android 13, les applis que vous installez ont besoin de votre autorisation pour envoyer des notifications. Touchez pour modifier cette autorisation pour les applis existantes."</string>
<string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Me rappeler plus tard"</string>
<string name="review_notification_settings_dismiss" msgid="4160916504616428294">"Fermer"</string>
<string name="notification_app_name_system" msgid="3045196791746735601">"Système"</string>
<string name="notification_app_name_settings" msgid="9088548800899952531">"Paramètres"</string>
<string name="notification_appops_camera_active" msgid="8177643089272352083">"Appareil photo"</string>
<string name="notification_appops_microphone_active" msgid="581333393214739332">"Microphone"</string>
- <string name="notification_appops_overlay_active" msgid="5571732753262836481">"superpose du contenu par-dessus d\'autres applications à l\'écran"</string>
+ <string name="notification_appops_overlay_active" msgid="5571732753262836481">"superpose du contenu par-dessus d\'autres applis à l\'écran"</string>
<string name="notification_feedback_indicator" msgid="663476517711323016">"Envoyer des commentaires"</string>
<string name="notification_feedback_indicator_alerted" msgid="6552871804121942099">"La notification a été automatiquement élevée à la catégorie Par défaut. Touchez pour envoyer des commentaires."</string>
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Cette notification a été rétrogradée à Silencieuse. Touchez pour envoyer des commentaires."</string>
@@ -2173,7 +2168,7 @@
<string name="battery_saver_charged_notification_summary" product="tablet" msgid="4426317048139996888">"La tablette est suffisamment chargée. Ces fonctionnalités ne sont plus restreintes."</string>
<string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"L\'appareil est suffisamment chargé. Ces fonctionnalités ne sont plus restreintes."</string>
<string name="mime_type_folder" msgid="2203536499348787650">"Dossier"</string>
- <string name="mime_type_apk" msgid="3168784749499623902">"Application Android"</string>
+ <string name="mime_type_apk" msgid="3168784749499623902">"Appli Android"</string>
<string name="mime_type_generic" msgid="4606589110116560228">"Fichier"</string>
<string name="mime_type_generic_ext" msgid="9220220924380909486">"Fichier <xliff:g id="EXTENSION">%1$s</xliff:g>"</string>
<string name="mime_type_audio" msgid="4933450584432509875">"Son"</string>
@@ -2194,11 +2189,11 @@
<string name="car_loading_profile" msgid="8219978381196748070">"Chargement en cours…"</string>
<string name="file_count" msgid="3220018595056126969">"{count,plural, =1{{file_name} + # fichier}one{{file_name} + # fichier}many{{file_name} + # fichiers}other{{file_name} + # fichiers}}"</string>
<string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"Aucune recommandation de personnes avec lesquelles effectuer un partage"</string>
- <string name="chooser_all_apps_button_label" msgid="3230427756238666328">"Liste des applications"</string>
- <string name="usb_device_resolve_prompt_warn" msgid="325871329788064199">"Cette application n\'a pas été autorisée à effectuer des enregistrements, mais elle pourrait capturer du contenu audio par l\'intermédiaire de cet appareil USB."</string>
+ <string name="chooser_all_apps_button_label" msgid="3230427756238666328">"Liste des applis"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="325871329788064199">"Cette appli n\'a pas été autorisée à effectuer des enregistrements, mais elle pourrait capturer du contenu audio par l\'intermédiaire de cet appareil USB."</string>
<string name="accessibility_system_action_home_label" msgid="3234748160850301870">"Accueil"</string>
<string name="accessibility_system_action_back_label" msgid="4205361367345537608">"Retour"</string>
- <string name="accessibility_system_action_recents_label" msgid="4782875610281649728">"Applications récentes"</string>
+ <string name="accessibility_system_action_recents_label" msgid="4782875610281649728">"Applis récentes"</string>
<string name="accessibility_system_action_notifications_label" msgid="6083767351772162010">"Notifications"</string>
<string name="accessibility_system_action_quick_settings_label" msgid="4583900123506773783">"Paramètres rapides"</string>
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Boîte de dialogue sur l\'alimentation"</string>
@@ -2227,22 +2222,22 @@
<string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Affichage personnel"</string>
<string name="resolver_work_tab_accessibility" msgid="4753168230363802734">"Affichage professionnel"</string>
<string name="resolver_cross_profile_blocked" msgid="3014597376026044840">"Bloqué par votre administrateur informatique"</string>
- <string name="resolver_cant_share_with_work_apps_explanation" msgid="9071442683080586643">"Impossible de partager ce contenu avec des applications professionnelles"</string>
- <string name="resolver_cant_access_work_apps_explanation" msgid="1129960195389373279">"Impossible d\'ouvrir ce contenu avec des applications professionnelles"</string>
- <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6349766201904601544">"Impossible de partager ce contenu avec des applications personnelles"</string>
- <string name="resolver_cant_access_personal_apps_explanation" msgid="1679399548862724359">"Impossible d\'ouvrir ce contenu avec des applications personnelles"</string>
- <string name="resolver_turn_on_work_apps" msgid="1535946298236678122">"Les applications professionnelles sont interrompues"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="9071442683080586643">"Impossible de partager ce contenu avec des applis professionnelles"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1129960195389373279">"Impossible d\'ouvrir ce contenu avec des applis professionnelles"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6349766201904601544">"Impossible de partager ce contenu avec des applis personnelles"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="1679399548862724359">"Impossible d\'ouvrir ce contenu avec des applis personnelles"</string>
+ <string name="resolver_turn_on_work_apps" msgid="1535946298236678122">"Les applis professionnelles sont interrompues"</string>
<string name="resolver_switch_on_work" msgid="4527096360772311894">"Réactiver"</string>
- <string name="resolver_no_work_apps_available" msgid="3298291360133337270">"Aucune application professionnelle"</string>
- <string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"Aucune application personnelle"</string>
+ <string name="resolver_no_work_apps_available" msgid="3298291360133337270">"Aucune appli professionnelle"</string>
+ <string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"Aucune appli personnelle"</string>
<string name="miniresolver_open_work" msgid="6286176185835401931">"Ouvrir le profil professionnel de <xliff:g id="APP">%s</xliff:g>?"</string>
<string name="miniresolver_open_in_personal" msgid="807427577794490375">"Ouvrir <xliff:g id="APP">%s</xliff:g> dans le profil personnel?"</string>
<string name="miniresolver_open_in_work" msgid="941341494673509916">"Ouvrir <xliff:g id="APP">%s</xliff:g> dans le profil professionnel?"</string>
- <string name="miniresolver_call_in_work" msgid="528779988307529039">"Appeler à partir de l\'application professionnelle?"</string>
- <string name="miniresolver_switch_to_work" msgid="1042640606122638596">"Passer à l\'application professionnelle?"</string>
- <string name="miniresolver_call_information" msgid="6739417525304184083">"Votre organisation vous autorise à passer des appels uniquement à partir d\'applications professionnelles"</string>
- <string name="miniresolver_sms_information" msgid="4311292661329483088">"Votre organisation vous autorise à envoyer des messages uniquement à partir d\'applications professionnelles"</string>
- <string name="miniresolver_private_space_phone_information" msgid="4469511223312488570">"Vous ne pouvez passer des appels téléphoniques qu\'à partir de votre application Téléphone personnelle. Les appels passés à l\'aide de cette dernière seront ajoutés à votre historique personnel des appels."</string>
+ <string name="miniresolver_call_in_work" msgid="528779988307529039">"Appeler à partir de l\'appli professionnelle?"</string>
+ <string name="miniresolver_switch_to_work" msgid="1042640606122638596">"Passer à l\'appli professionnelle?"</string>
+ <string name="miniresolver_call_information" msgid="6739417525304184083">"Votre organisation vous autorise à passer des appels uniquement à partir d\'applis professionnelles"</string>
+ <string name="miniresolver_sms_information" msgid="4311292661329483088">"Votre organisation vous autorise à envoyer des messages uniquement à partir d\'applis professionnelles"</string>
+ <string name="miniresolver_private_space_phone_information" msgid="4469511223312488570">"Vous ne pouvez passer des appels téléphoniques qu\'à partir de votre appli Téléphone personnelle. Les appels passés à l\'aide de cette dernière seront ajoutés à votre historique personnel des appels."</string>
<string name="miniresolver_private_space_messages_information" msgid="111285656327622118">"Vous ne pouvez envoyer des messages texte qu\'à partir de votre appli Messages personnelle."</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Utiliser le navigateur du profil personnel"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"Utiliser le navigateur du profil professionnel"</string>
@@ -2366,35 +2361,35 @@
<string name="dismiss_action" msgid="1728820550388704784">"Fermer"</string>
<string name="sensor_privacy_start_use_mic_notification_content_title" msgid="2420858361276370367">"Débloquer le microphone de l\'appareil"</string>
<string name="sensor_privacy_start_use_camera_notification_content_title" msgid="7287720213963466672">"Débloquer l\'appareil photo de l\'appareil"</string>
- <string name="sensor_privacy_start_use_notification_content_text" msgid="7595608891015777346">"Pour &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; ainsi que toutes les applications et tous les services"</string>
+ <string name="sensor_privacy_start_use_notification_content_text" msgid="7595608891015777346">"Pour &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; ainsi que toutes les applis et tous les services"</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7089318886628390827">"Débloquer"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Confidentialité des capteurs"</string>
- <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Icône de l\'application"</string>
- <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Image de marque de l\'application"</string>
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Icône de l\'appli"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Image de marque de l\'appli"</string>
<string name="view_and_control_notification_title" msgid="4300765399209912240">"Vérifiez les paramètres d\'accès"</string>
<string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> peut voir et contrôler votre écran. Touchez pour examiner."</string>
<string name="ui_translation_accessibility_translated_text" msgid="3197547218178944544">"Message <xliff:g id="MESSAGE">%1$s</xliff:g> traduit."</string>
<string name="ui_translation_accessibility_translation_finished" msgid="3057830947610088465">"Message traduit : <xliff:g id="FROM_LANGUAGE">%1$s</xliff:g> vers <xliff:g id="TO_LANGUAGE">%2$s</xliff:g>."</string>
<string name="notification_channel_abusive_bg_apps" msgid="6092140213264920355">"Activité en arrière-plan"</string>
- <string name="notification_title_abusive_bg_apps" msgid="994230770856147656">"Une application décharge votre pile"</string>
- <string name="notification_title_long_running_fgs" msgid="8170284286477131587">"Une application est toujours active"</string>
+ <string name="notification_title_abusive_bg_apps" msgid="994230770856147656">"Une appli décharge votre pile"</string>
+ <string name="notification_title_long_running_fgs" msgid="8170284286477131587">"Une appli est toujours active"</string>
<string name="notification_content_abusive_bg_apps" msgid="5296898075922695259">"<xliff:g id="APP">%1$s</xliff:g> s\'exécute en arrière-plan. Touchez pour gérer l\'utilisation de la pile."</string>
- <string name="notification_content_long_running_fgs" msgid="8258193410039977101">"<xliff:g id="APP">%1$s</xliff:g> peut avoir une incidence sur l\'autonomie de la pile. Touchez pour examiner les applications actives."</string>
- <string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Vérifier les applications actives"</string>
+ <string name="notification_content_long_running_fgs" msgid="8258193410039977101">"<xliff:g id="APP">%1$s</xliff:g> peut avoir une incidence sur l\'autonomie de la pile. Touchez pour examiner les applis actives."</string>
+ <string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Vérifier les applis actives"</string>
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Impossible d\'accéder à l\'appareil photo du téléphone à partir de votre <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Impossible d\'accéder à l\'appareil photo de la tablette à partir de votre <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"Vous ne pouvez pas y accéder lorsque vous utilisez la diffusion en continu. Essayez sur votre téléphone à la place."</string>
<string name="vdm_pip_blocked" msgid="4036107522497281397">"Impossible d\'afficher des incrustations d\'image pendant une diffusion en continu"</string>
<string name="system_locale_title" msgid="711882686834677268">"Paramètre système par défaut"</string>
<string name="default_card_name" msgid="9198284935962911468">"CARTE <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
- <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Autorisation du profil de la montre de l\'application compagnon pour gérer les montres"</string>
- <string name="permdesc_companionProfileWatch" msgid="5655698581110449397">"Autorise une application compagnon à gérer les montres."</string>
+ <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Autorisation du profil de la montre de l\'appli compagnon pour gérer les montres"</string>
+ <string name="permdesc_companionProfileWatch" msgid="5655698581110449397">"Autorise une appli compagnon à gérer les montres."</string>
<string name="permlab_observeCompanionDevicePresence" msgid="9008994909653990465">"Surveiller la présence d\'un appareil compagnon"</string>
- <string name="permdesc_observeCompanionDevicePresence" msgid="3011699826788697852">"Autorise une application compagnon à surveiller la présence d\'un appareil compagnon lorsque les appareils sont à proximité ou éloignés."</string>
- <string name="permlab_deliverCompanionMessages" msgid="3931552294842980887">"Transmettre les messages des applications compagnons"</string>
- <string name="permdesc_deliverCompanionMessages" msgid="2170847384281412850">"Autorise une application compagnon à transmettre des messages à d\'autres appareils."</string>
+ <string name="permdesc_observeCompanionDevicePresence" msgid="3011699826788697852">"Autorise une appli compagnon à surveiller la présence d\'un appareil compagnon lorsque les appareils sont à proximité ou éloignés."</string>
+ <string name="permlab_deliverCompanionMessages" msgid="3931552294842980887">"Transmettre les messages des applis compagnons"</string>
+ <string name="permdesc_deliverCompanionMessages" msgid="2170847384281412850">"Autorise une appli compagnon à transmettre des messages à d\'autres appareils."</string>
<string name="permlab_startForegroundServicesFromBackground" msgid="6363004936218638382">"Lancer les services d\'avant-plan à partir de l\'arrière-plan"</string>
- <string name="permdesc_startForegroundServicesFromBackground" msgid="4071826571656001537">"Permet à une application compagnon en arrière-plan de lancer des services d\'avant-plan."</string>
+ <string name="permdesc_startForegroundServicesFromBackground" msgid="4071826571656001537">"Permet à une appli compagnon en arrière-plan de lancer des services d\'avant-plan."</string>
<string name="mic_access_on_toast" msgid="2666925317663845156">"Le microphone est accessible"</string>
<string name="mic_access_off_toast" msgid="8111040892954242437">"Le microphone est bloqué"</string>
<string name="connected_display_unavailable_notification_title" msgid="5265409360902073556">"Impossible de dupliquer l\'écran"</string>
@@ -2437,17 +2432,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Fonctionnement"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"En attente…"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Configurer le Déverrouillage par empreinte digitale à nouveau"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"L\'empreinte digitale <xliff:g id="FINGERPRINT">%s</xliff:g> ne peut plus être reconnue."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"Les empreintes digitales <xliff:g id="FINGERPRINT_0">%1$s</xliff:g> et <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> ne peuvent plus être reconnues."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"L\'empreinte digitale <xliff:g id="FINGERPRINT">%s</xliff:g> ne peut plus être reconnue. Reconfigurez le Déverrouillage par empreinte digitale."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"Les empreintes digitales <xliff:g id="FINGERPRINT_0">%1$s</xliff:g> et <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> ne peuvent plus être reconnues. Reconfigurez le Déverrouillage par empreinte digitale."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"Configurer le Déverrouillage par reconnaissance faciale à nouveau"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"Votre modèle facial ne peut plus être reconnu. Reconfigurez le Déverrouillage par reconnaissance faciale."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Configurer"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Plus tard"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"Alarme pour <xliff:g id="USER_NAME">%s</xliff:g>"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 4bcf9a649770..e4b87edb6cc5 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -266,8 +266,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"Rapport de bug"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Fermer la session"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Capture d\'écran"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"Signaler un bug"</string>
<string name="bugreport_message" msgid="5212529146119624326">"Cela permet de recueillir des informations concernant l\'état actuel de votre appareil. Ces informations sont ensuite envoyées sous forme d\'e-mail. Merci de patienter pendant la préparation du rapport de bug. Cette opération peut prendre quelques instants."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"Rapport interactif"</string>
@@ -1768,12 +1766,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"La fonctionnalité s\'ouvrira la prochaine fois que vous appuierez sur le bouton Accessibilité"</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"La fonctionnalité s\'ouvrira la prochaine fois que vous utiliserez ce raccourci. Balayez du bas de l\'écran vers le haut avec deux doigts et relâchez rapidement."</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"La fonctionnalité s\'ouvrira la prochaine fois que vous utiliserez ce raccourci. Balayez du bas de l\'écran vers le haut avec trois doigts et relâchez rapidement."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Agrandissement"</string>
<string name="user_switched" msgid="7249833311585228097">"Utilisateur actuel : <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="user_switching_message" msgid="1912993630661332336">"Passage à <xliff:g id="NAME">%1$s</xliff:g>..."</string>
@@ -2437,17 +2432,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Fonctionnement"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"En attente…"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Reconfigurer le déverrouillage par empreinte digitale"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> ne peut plus être reconnue."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> et <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> ne peuvent plus être reconnues."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"<xliff:g id="FINGERPRINT">%s</xliff:g> ne peut plus être reconnue. Reconfigurez le déverrouillage par empreinte digitale."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> et <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> ne peuvent plus être reconnues. Reconfigurez le déverrouillage par empreinte digitale."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"Reconfigurer le déverrouillage par reconnaissance faciale"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"Votre empreinte faciale ne peut plus être reconnue. Reconfigurez le déverrouillage par reconnaissance faciale."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Configuration"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Pas maintenant"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"Alarme pour <xliff:g id="USER_NAME">%s</xliff:g>"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 6bfebb405cda..2adedd5a2ca4 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -265,8 +265,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"Informe de erros"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Finalizar a sesión"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Capt. pantalla"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"Informe de erros"</string>
<string name="bugreport_message" msgid="5212529146119624326">"Este informe recompilará información acerca do estado actual do teu dispositivo para enviala en forma de mensaxe de correo electrónico. O informe de erros tardará un pouco en completarse desde o seu inicio ata que estea preparado para enviarse, polo que che recomendamos que teñas paciencia."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"Informe interactivo"</string>
@@ -1767,12 +1765,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"A función abrirase cando volvas tocar o botón Accesibilidade"</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"A función abrirase cando volvas usar este atallo. Pasa dous dedos desde a parte inferior da pantalla e solta rapidamente."</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"A función abrirase cando volvas usar este atallo. Pasa tres dedos desde a parte inferior da pantalla e solta rapidamente."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Ampliación"</string>
<string name="user_switched" msgid="7249833311585228097">"Usuario actual <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="1912993630661332336">"Cambiando a <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2436,17 +2431,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Como funciona?"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Pendente..."</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Configura de novo o desbloqueo dactilar"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> xa non se recoñece."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> e <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> xa non se recoñecen."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"<xliff:g id="FINGERPRINT">%s</xliff:g> xa non se recoñece. Configura de novo o desbloqueo dactilar."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> e <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> xa non se recoñecen. Configura de novo o desbloqueo dactilar."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"Configura de novo o desbloqueo facial"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"Xa non se recoñece o teu modelo facial. Configura de novo o desbloqueo facial."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Configurar"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Agora non"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"Alarma para <xliff:g id="USER_NAME">%s</xliff:g>"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index fd2134aa96ba..6a01682acf2e 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -265,8 +265,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"બગ રિપોર્ટ"</string>
<string name="global_action_logout" msgid="6093581310002476511">"સત્ર સમાપ્ત કરો"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"સ્ક્રીનશૉટ"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"બગ રિપોર્ટ"</string>
<string name="bugreport_message" msgid="5212529146119624326">"આ, એક ઇ-મેઇલ સંદેશ તરીકે મોકલવા માટે, તમારા વર્તમાન ઉપકરણ સ્થિતિ વિશેની માહિતી એકત્રિત કરશે. એક બગ રિપોર્ટ પ્રારંભ કરીને તે મોકલવા માટે તૈયાર ન થઈ જાય ત્યાં સુધી તેમાં થોડો સમય લાગશે; કૃપા કરીને ધીરજ રાખો."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"ક્રિયાપ્રતિક્રિયાત્મક રિપોર્ટ"</string>
@@ -1767,12 +1765,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"તમે આગલી વાર જ્યારે ઍક્સેસિબિલિટી બટન પર ટૅપ કરશો, ત્યારે આ સુવિધા ચાલુ થશે"</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"તમે આગલી વાર જ્યારે આ શૉર્ટકટનો ઉપયોગ કરશો, ત્યારે આ સુવિધા ચાલુ થશે. તમારી સ્ક્રીનની સૌથી નીચેથી 2 આંગળી વડે ઉપરની દિશાએ સ્વાઇપ કરો અને ઝડપથી છોડી દો."</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"તમે આગલી વાર જ્યારે આ શૉર્ટકટનો ઉપયોગ કરશો, ત્યારે આ સુવિધા ચાલુ થશે. તમારી સ્ક્રીનની સૌથી નીચેથી 3 આંગળી વડે ઉપરની દિશાએ સ્વાઇપ કરો અને ઝડપથી છોડી દો."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"મોટું કરવું"</string>
<string name="user_switched" msgid="7249833311585228097">"વર્તમાન વપરાશકર્તા <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="1912993630661332336">"<xliff:g id="NAME">%1$s</xliff:g> પર સ્વિચ કરી રહ્યાં છે…"</string>
@@ -2436,17 +2431,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"તેની કામ કરવાની રીત"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"બાકી..."</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"ફિંગરપ્રિન્ટ અનલૉક સુવિધાનું ફરી સેટઅપ કરો"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"હવે <xliff:g id="FINGERPRINT">%s</xliff:g> ઓળખી શકાતી નથી."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"હવે <xliff:g id="FINGERPRINT_0">%1$s</xliff:g> અને <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> ઓળખી શકાતી નથી."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"હવે <xliff:g id="FINGERPRINT">%s</xliff:g> ઓળખી શકાતી નથી. ફિંગરપ્રિન્ટ અનલૉક સુવિધાનું ફરી સેટઅપ કરો."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"હવે <xliff:g id="FINGERPRINT_0">%1$s</xliff:g> અને <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> ઓળખી શકાતી નથી. ફિંગરપ્રિન્ટ અનલૉક સુવિધાનું ફરી સેટઅપ કરો."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"ફેસ અનલૉક સુવિધાનું ફરી સેટઅપ કરો"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"હવે તમારા ચહેરાનું મૉડલ ઓળખી શકાતું નથી. ફેસ અનલૉક સુવિધાનું ફરી સેટઅપ કરો."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"સેટઅપ કરો"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"હમણાં નહીં"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"<xliff:g id="USER_NAME">%s</xliff:g> માટે અલાર્મ"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 84df1165b091..04ee203cc119 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -265,8 +265,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"गड़बड़ी की रिपोर्ट"</string>
<string name="global_action_logout" msgid="6093581310002476511">"सत्र खत्म करें"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"स्क्रीनशॉट"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"गड़बड़ी की रिपोर्ट"</string>
<string name="bugreport_message" msgid="5212529146119624326">"इससे ईमेल भेजने के लिए, आपके डिवाइस की मौजूदा स्थिति से जुड़ी जानकारी इकट्ठा की जाएगी. गड़बड़ी की रिपोर्ट बनना शुरू होने से लेकर भेजने के लिए तैयार होने तक कुछ समय लगेगा; कृपया इंतज़ार करें."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"सहभागी रिपोर्ट"</string>
@@ -1200,7 +1198,7 @@
<string name="low_internal_storage_view_text" msgid="8172166728369697835">"हो सकता है कुछ सिस्टम फ़ंक्शन काम नहीं करें"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="7368968163411251788">"सिस्टम के लिए ज़रूरी मेमोरी नहीं है. पक्का करें कि आपके पास 250एमबी की खाली जगह है और फिर से शुरू करें."</string>
<string name="app_running_notification_title" msgid="8985999749231486569">"<xliff:g id="APP_NAME">%1$s</xliff:g> चल रहा है"</string>
- <string name="app_running_notification_text" msgid="5120815883400228566">"ज़्यादा जानकारी के लिए या ऐप्लिकेशन को रोकने के लिए छूएं."</string>
+ <string name="app_running_notification_text" msgid="5120815883400228566">"ऐप्लिकेशन को रोकने या ज़्यादा जानकारी के लिए टैप करें."</string>
<string name="ok" msgid="2646370155170753815">"ठीक है"</string>
<string name="cancel" msgid="6908697720451760115">"रद्द करें"</string>
<string name="yes" msgid="9069828999585032361">"ठीक है"</string>
@@ -1441,8 +1439,8 @@
<string name="fast_scroll_numeric_alphabet" msgid="2529539945421557329">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="alert_windows_notification_channel_group_name" msgid="6063891141815714246">"दूसरे ऐप्लिकेशन के ऊपर दिखाए जाने का ऐक्सेस"</string>
<string name="alert_windows_notification_channel_name" msgid="3437528564303192620">"<xliff:g id="NAME">%s</xliff:g> अन्य ऐप्लिकेशन के ऊपर दिखाई दे रहा है"</string>
- <string name="alert_windows_notification_title" msgid="6331662751095228536">"<xliff:g id="NAME">%s</xliff:g> अन्य ऐप पर दिखाई दे रहा है"</string>
- <string name="alert_windows_notification_message" msgid="6538171456970725333">"अगर आप नहीं चाहते कि <xliff:g id="NAME">%s</xliff:g> इस सुविधा का उपयोग करे, तो सेटिंग खोलने और उसे बंद करने के लिए टैप करें."</string>
+ <string name="alert_windows_notification_title" msgid="6331662751095228536">"<xliff:g id="NAME">%s</xliff:g> दूसरे ऐप के ऊपर दिख रहा है"</string>
+ <string name="alert_windows_notification_message" msgid="6538171456970725333">"अगर <xliff:g id="NAME">%s</xliff:g> को इस सुविधा का इस्तेमाल करने की अनुमति नहीं देनी है, तो इसे बंद करने के लिए सेटिंग पर जाएं."</string>
<string name="alert_windows_notification_turn_off_action" msgid="7805857234839123780">"बंद करें"</string>
<string name="ext_media_checking_notification_title" msgid="8299199995416510094">"<xliff:g id="NAME">%s</xliff:g> ढूंढा जा रहा है…"</string>
<string name="ext_media_checking_notification_message" msgid="2231566971425375542">"मौजूदा सामग्री की जाँच की जा रही है"</string>
@@ -2433,17 +2431,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"यह सेटिंग कैसे काम करती है"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"प्रोसेस जारी है..."</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"फ़िंगरप्रिंट अनलॉक की सुविधा दोबारा सेट अप करें"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"अब <xliff:g id="FINGERPRINT">%s</xliff:g> की पहचान नहीं की जा सकती."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"अब <xliff:g id="FINGERPRINT_0">%1$s</xliff:g> और <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> की पहचान नहीं की जा सकती."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"अब <xliff:g id="FINGERPRINT">%s</xliff:g> की पहचान नहीं की जा सकती. फ़िंगरप्रिंट अनलॉक की सुविधा दोबारा सेट अप करें."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"अब <xliff:g id="FINGERPRINT_0">%1$s</xliff:g> और <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> की पहचान नहीं की जा सकती. फ़िंगरप्रिंट अनलॉक की सुविधा दोबारा सेट अप करें."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"फ़ेस अनलॉक की सुविधा को दोबारा सेट अप करें"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"अब आपके चेहरे के मॉडल की पहचान नहीं की जा सकती. फ़ेस अनलॉक की सुविधा को दोबारा सेट अप करें."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"सेट अप करें"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"अभी नहीं"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"<xliff:g id="USER_NAME">%s</xliff:g> के लिए अलार्म"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index ace37279027c..acb6d042e3b8 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -266,8 +266,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"Izvješće o programskim pogreškama"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Završi sesiju"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Snimka zaslona"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"Izvješće o programskim pogreškama"</string>
<string name="bugreport_message" msgid="5212529146119624326">"Time će se prikupiti podaci o trenutačnom stanju vašeg uređaja koje ćete nam poslati u e-poruci. Za pripremu izvješća o programskoj pogrešci potrebno je nešto vremena pa vas molimo za strpljenje."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"Interaktivno izvješće"</string>
@@ -1768,12 +1766,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"Značajka će se otvoriti sljedeći put kad dodirnete gumb za pristupačnost"</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"Značajka će se otvoriti sljedeći put kad upotrijebite ovaj prečac. Nakratko prijeđite dvama prstima s dna zaslona."</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"Značajka će se otvoriti sljedeći put kad upotrijebite ovaj prečac. Nakratko prijeđite s dna zaslona trima prstima."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Povećavanje"</string>
<string name="user_switched" msgid="7249833311585228097">"Trenutačni korisnik <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="1912993630661332336">"Prebacivanje na korisnika <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2437,17 +2432,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Kako to funkcionira"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Na čekanju..."</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Ponovno postavite otključavanje otiskom prsta"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> više se ne prepoznaje."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> i <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> više se ne prepoznaju."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"<xliff:g id="FINGERPRINT">%s</xliff:g> više se ne prepoznaje. Ponovo postavite otključavanje otiskom prsta."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> i <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> više se ne prepoznaju. Ponovo postavite otključavanje otiskom prsta."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"Ponovno postavite otključavanje licem"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"Vaš model lica više se ne prepoznaje. Ponovo postavite otključavanje licem."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Postavi"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Ne sad"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"Alarm za korisnika <xliff:g id="USER_NAME">%s</xliff:g>"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 23b5fee78b61..5002b0939589 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -265,8 +265,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"Programhiba bejelentése"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Munkamenet befejezése"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Képernyőkép"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"Programhiba bejelentése"</string>
<string name="bugreport_message" msgid="5212529146119624326">"Ezzel információt fog gyűjteni az eszköz jelenlegi állapotáról, amelyet a rendszer e-mailben fog elküldeni. Kérjük, legyen türelemmel, amíg a hibajelentés elkészül, és küldhető állapotba kerül."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"Interaktív jelentés"</string>
@@ -1767,12 +1765,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"A funkció a Kisegítő lehetőségek gombra való következő koppintáskor lesz megnyitva"</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"A funkció a gyorsparancs következő használatakor lesz megnyitva. Csúsztasson felfelé két ujjal a képernyő aljáról, majd emelje fel gyorsan az ujjait."</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"A funkció a gyorsparancs következő használatakor lesz megnyitva. Csúsztasson felfelé három ujjal a képernyő aljáról, majd emelje fel gyorsan az ujjait."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Nagyítás"</string>
<string name="user_switched" msgid="7249833311585228097">"<xliff:g id="NAME">%1$s</xliff:g> az aktuális felhasználó."</string>
<string name="user_switching_message" msgid="1912993630661332336">"Átváltás erre: <xliff:g id="NAME">%1$s</xliff:g>..."</string>
@@ -2436,17 +2431,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Hogyan működik?"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Függőben…"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"A Feloldás ujjlenyomattal funkció újbóli beállítása"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"A következő már nem felismerhető: <xliff:g id="FINGERPRINT">%s</xliff:g>."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"A következők már nem felismerhetők: <xliff:g id="FINGERPRINT_0">%1$s</xliff:g> és <xliff:g id="FINGERPRINT_1">%2$s</xliff:g>."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"A következő már nem felismerhető: <xliff:g id="FINGERPRINT">%s</xliff:g>. Állítsa be újra a Feloldás ujjlenyomattal funkciót."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"A következők már nem felismerhetők: <xliff:g id="FINGERPRINT_0">%1$s</xliff:g> és <xliff:g id="FINGERPRINT_1">%2$s</xliff:g>. Állítsa be újra a Feloldás ujjlenyomattal funkciót."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"Állítsa be újra az Arcalapú feloldást"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"Az arcmodellje már nem felismerhető. Állítsa be újra az Arcalapú feloldást."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Beállítás"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Most nem"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"Riasztás <xliff:g id="USER_NAME">%s</xliff:g> részére"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 4f9d478020af..2a5bdfc89183 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -265,8 +265,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"Հաղորդում վրիպակի մասին"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Ավարտել աշխատաշրջանը"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Սքրինշոթ"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"Հաղորդում վրիպակի մասին"</string>
<string name="bugreport_message" msgid="5212529146119624326">"Սա տեղեկություններ կհավաքագրի ձեր սարքի առկա կարգավիճակի մասին և կուղարկի այն էլեկտրոնային նամակով: Որոշակի ժամանակ կպահանջվի վրիպակի մասին զեկուցելու պահից սկսած մինչ ուղարկելը: Խնդրում ենք փոքր-ինչ համբերատար լինել:"</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"Ինտերակտիվ զեկույց"</string>
@@ -1767,12 +1765,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"Գործառույթը կբացվի հաջորդ անգամ, երբ սեղմեք «Հատուկ գործառույթներ» կոճակը"</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"Գործառույթը կբացվի հաջորդ անգամ, երբ օգտագործեք այս դյուրանցումը։ Երկու մատը էկրանի ներքևից սահեցրեք վերև և արագ բաց թողեք։"</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"Գործառույթը կբացվի հաջորդ անգամ, երբ օգտագործեք այս դյուրանցումը։ Երեք մատը էկրանի ներքևից սահեցրեք վերև և արագ բաց թողեք։"</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Խոշորացում"</string>
<string name="user_switched" msgid="7249833311585228097">"Ներկայիս օգտատերը <xliff:g id="NAME">%1$s</xliff:g>:"</string>
<string name="user_switching_message" msgid="1912993630661332336">"Անցում <xliff:g id="NAME">%1$s</xliff:g> պրոֆիլին..."</string>
@@ -2436,17 +2431,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Ինչպես է դա աշխատում"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Առկախ է…"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Նորից կարգավորեք մատնահետքով ապակողպումը"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> մատնահետքն այլևս չի կարող ճանաչվել։"</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> և <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> մատնահետքերն այլևս չեն կարող ճանաչվել։"</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"<xliff:g id="FINGERPRINT">%s</xliff:g> մատնահետքն այլևս չի կարող ճանաչվել։ Նորից կարգավորեք մատնահետքով ապակողպումը։"</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> և <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> մատնահետքերն այլևս չեն կարող ճանաչվել։ Նորից կարգավորեք մատնահետքով ապակողպումը։"</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"Նորից կարգավորեք դեմքով ապակողպումը"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"Ձեր դեմքի նմուշն այլևս չի կարող ճանաչվել։ Նորից կարգավորեք դեմքով ապակողպումը։"</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Կարգավորել"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Ոչ հիմա"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"<xliff:g id="USER_NAME">%s</xliff:g>-ի զարթուցիչ"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 2fabef385270..f861728a32aa 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -265,8 +265,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"Laporan bug"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Akhiri sesi"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Screenshot"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"Laporan bug"</string>
<string name="bugreport_message" msgid="5212529146119624326">"Ini akan mengumpulkan informasi status perangkat Anda saat ini, untuk dikirimkan sebagai pesan email. Harap bersabar, mungkin perlu waktu untuk memulai laporan bug hingga siap dikirim."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"Laporan interaktif"</string>
@@ -1767,12 +1765,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"Fitur akan terbuka setelah Anda mengetuk tombol aksesibilitas"</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"Fitur akan terbuka setelah Anda menggunakan pintasan ini. Geser ke atas dengan 2 jari dari bawah layar, lalu lepaskan dengan cepat."</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"Fitur akan terbuka setelah Anda menggunakan pintasan ini. Geser ke atas dengan 3 jari dari bawah layar, lalu lepaskan dengan cepat."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Pembesaran"</string>
<string name="user_switched" msgid="7249833311585228097">"Pengguna saat ini <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="1912993630661332336">"Beralih ke <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2436,17 +2431,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Cara kerjanya"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Tertunda..."</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Siapkan Buka dengan Sidik Jari lagi"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> tidak dapat dikenali lagi."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> dan <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> tidak dapat dikenali lagi."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"<xliff:g id="FINGERPRINT">%s</xliff:g> tidak dapat dikenali lagi. Siapkan Buka dengan Sidik Jari lagi."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> dan <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> tidak dapat dikenali lagi. Siapkan Buka dengan Sidik Jari lagi."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"Siapkan Buka dengan Wajah lagi"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"Model wajah Anda tidak dapat dikenali lagi. Siapkan Buka dengan Wajah lagi."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Penyiapan"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Lain kali"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"Alarm untuk <xliff:g id="USER_NAME">%s</xliff:g>"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index dd47cebcdf49..21d57ea59d3c 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -265,8 +265,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"Villutilkynning"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Ljúka lotu"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Skjámynd"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"Villutilkynning"</string>
<string name="bugreport_message" msgid="5212529146119624326">"Þetta safnar upplýsingum um núverandi stöðu tækisins til að senda með tölvupósti. Það tekur smástund frá því villutilkynningin er ræst og þar til hún er tilbúin til sendingar – sýndu biðlund."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"Gagnvirk skýrsla"</string>
@@ -1767,12 +1765,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"Eiginleikinn opnast næst þegar þú ýtir á aðgengishnappinn"</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"Eiginleikinn opnast næst þegar þú notar þessa flýtileið Strjúktu upp með 2 fingrum frá neðsta hluta skjásins og slepptu hratt."</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"Eiginleikinn opnast næst þegar þú notar þessa flýtileið Strjúktu upp með 3 fingrum frá neðsta hluta skjásins og slepptu hratt."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Stækkun"</string>
<string name="user_switched" msgid="7249833311585228097">"Núverandi notandi <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="1912993630661332336">"Skiptir yfir á <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2436,17 +2431,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Svona virkar þetta"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Í bið…"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Setja upp fingrafarskenni aftur"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"Ekki er hægt að bera kennsl á <xliff:g id="FINGERPRINT">%s</xliff:g> lengur."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"Ekki er hægt að bera kennsl á <xliff:g id="FINGERPRINT_0">%1$s</xliff:g> og <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> lengur."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"Ekki er hægt að bera kennsl á <xliff:g id="FINGERPRINT">%s</xliff:g> lengur. Settu upp fingrafarskenni aftur."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"Ekki er hægt að bera kennsl á <xliff:g id="FINGERPRINT_0">%1$s</xliff:g> og <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> lengur. Settu upp fingrafarskenni aftur."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"Setja upp andlitskenni aftur"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"Ekki er hægt að bera kennsl á andlitslíkanið þitt lengur. Settu upp andlitskenni aftur."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Setja upp"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Ekki núna"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"Viðvörun fyrir <xliff:g id="USER_NAME">%s</xliff:g>"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 94b68b031deb..e99e9485ef43 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -266,8 +266,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"Segnalazione di bug"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Termina sessione"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Screenshot"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"Segnalazione di bug"</string>
<string name="bugreport_message" msgid="5212529146119624326">"Verranno raccolte informazioni sullo stato corrente del dispositivo che saranno inviate sotto forma di messaggio email. Passerà un po\' di tempo prima che la segnalazione di bug aperta sia pronta per essere inviata; ti preghiamo di avere pazienza."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"Report interattivo"</string>
@@ -2434,17 +2432,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Come funziona"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"In attesa…"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Riconfigura lo Sblocco con l\'Impronta"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> non può più essere riconosciuto."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> e <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> non possono più essere riconosciuti."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"<xliff:g id="FINGERPRINT">%s</xliff:g> non può più essere riconosciuto. Riconfigura lo Sblocco con l\'Impronta."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> e <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> non possono più essere riconosciuti. Riconfigura lo Sblocco con l\'Impronta."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"Riconfigura lo Sblocco con il Volto"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"Il tuo modello del volto non può più essere riconosciuto. Riconfigura lo Sblocco con il Volto."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Configura"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Non ora"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"Sveglia per: <xliff:g id="USER_NAME">%s</xliff:g>"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index f9b1d03b07dc..6a4cea6a5cf8 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -266,8 +266,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"דוח איתור באגים"</string>
<string name="global_action_logout" msgid="6093581310002476511">"סיום הפעלה"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"צילום מסך"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"דיווח על באג"</string>
<string name="bugreport_message" msgid="5212529146119624326">"הפעולה הזו תאסוף מידע על מצב המכשיר הנוכחי שלך כדי לשלוח אותו כהודעת אימייל. היא תימשך זמן קצר מרגע פתיחת הדיווח על הבאג ועד לשליחת ההודעה בפועל. יש להמתין בסבלנות."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"דוח אינטראקטיבי"</string>
@@ -2434,17 +2432,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"איך זה עובד"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"בהמתנה..."</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"הגדרה חוזרת של \'ביטול הנעילה בטביעת אצבע\'"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"כבר לא ניתן לזהות את <xliff:g id="FINGERPRINT">%s</xliff:g>."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"כבר לא ניתן לזהות את <xliff:g id="FINGERPRINT_0">%1$s</xliff:g> ואת <xliff:g id="FINGERPRINT_1">%2$s</xliff:g>."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"כבר לא ניתן לזהות את <xliff:g id="FINGERPRINT">%s</xliff:g>. הגדרה חוזרת של \'פתיחה בטביעת אצבע\'."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"כבר לא ניתן לזהות את <xliff:g id="FINGERPRINT_0">%1$s</xliff:g> ואת <xliff:g id="FINGERPRINT_1">%2$s</xliff:g>. הגדרה חוזרת של \'פתיחה בטביעת אצבע\'."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"הגדרה חוזרת של \'פתיחה ע\"י זיהוי הפנים\'"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"כבר לא ניתן לזהות את התבנית לזיהוי הפנים. הגדרה חוזרת של \'פתיחה בזיהוי פנים\'."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"הגדרה"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"לא עכשיו"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"שעון מעורר של <xliff:g id="USER_NAME">%s</xliff:g>"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index e97ff004b53e..743d58ef28f9 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -265,8 +265,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"バグレポート"</string>
<string name="global_action_logout" msgid="6093581310002476511">"セッションを終了"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"画面の保存"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"バグレポート"</string>
<string name="bugreport_message" msgid="5212529146119624326">"現在のデバイスの状態に関する情報が収集され、その内容がメールで送信されます。バグレポートが開始してから送信可能な状態となるまでには多少の時間がかかりますのでご了承ください。"</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"対話型レポート"</string>
@@ -2433,17 +2431,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"仕組み"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"保留中..."</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"指紋認証をもう一度設定してください"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g>を認識できなくなりました。"</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g>と<xliff:g id="FINGERPRINT_1">%2$s</xliff:g>を認識できなくなりました。"</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"<xliff:g id="FINGERPRINT">%s</xliff:g>を認識できなくなりました。指紋認証をもう一度設定してください。"</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g>と<xliff:g id="FINGERPRINT_1">%2$s</xliff:g>を認識できなくなりました。指紋認証をもう一度設定してください。"</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"顔認証をもう一度設定してください"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"顔モデルを認識できなくなりました。顔認証をもう一度設定してください。"</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"設定"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"後で"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"<xliff:g id="USER_NAME">%s</xliff:g> さんのアラーム"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 967877c9bcc9..45d8264e243c 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -265,8 +265,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"ხარვეზის ანგარიში"</string>
<string name="global_action_logout" msgid="6093581310002476511">"სესიის დასრულება"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"ეკრანის ანაბეჭდი"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"ხარვეზის ანგარიში"</string>
<string name="bugreport_message" msgid="5212529146119624326">"იგი შეაგროვებს ინფორმაციას თქვენი მოწყობილობის ამჟამინდელი მდგომარეობის შესახებ, რათა ის ელფოსტის შეტყობინების სახით გააგზავნოს. ხარვეზის ანგარიშის მომზადებასა და შეტყობინების გაგზავნას გარკვეული დრო სჭირდება. გთხოვთ, მოითმინოთ."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"ინტერაქტიული ანგარიში"</string>
@@ -2433,17 +2431,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"მუშაობის პრინციპი"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"მომლოდინე..."</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"ანაბეჭდით განბლოკვის ხელახლა დაყენება"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g>-ის ამოცნობა ვეღარ ხერხდება."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g>-ისა და <xliff:g id="FINGERPRINT_1">%2$s</xliff:g>-ის ამოცნობა ვეღარ ხერხდება."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"<xliff:g id="FINGERPRINT">%s</xliff:g>-ის ამოცნობა ვეღარ ხერხდება. დააყენეთ ანაბეჭდით განბლოკვა ხელახლა."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g>-ისა და <xliff:g id="FINGERPRINT_1">%2$s</xliff:g>-ის ამოცნობა ვეღარ ხერხდება. დააყენეთ ანაბეჭდით განბლოკვა ხელახლა."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"დააყენეთ სახით განბლოკვა ხელახლა"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"თქვენი სახის მოდელის ამოცნობა ვეღარ ხერხდება. დააყენეთ სახით განბლოკვა ხელახლა."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"დაყენება"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"ახლა არა"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"მაღვიძარა <xliff:g id="USER_NAME">%s</xliff:g>-ისთვის"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 9d3ee992e6ae..0393067d8275 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -265,8 +265,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"Вирус туралы хабарлау"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Сеансты аяқтау"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Скриншот"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"Қате туралы есеп"</string>
<string name="bugreport_message" msgid="5212529146119624326">"Құрылғының қазіргі күйі туралы ақпаратты жинап, электрондық хабармен жібереді. Есеп әзір болғанша біраз уақыт кетеді, шыдай тұрыңыз."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"Интерактивті есеп"</string>
@@ -1767,12 +1765,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"Келесіде арнайы мүмкіндіктер түймесін түрткенде, функция ашылады."</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"Келесіде осы жылдам пәрменді қолданғанда, функция ашылады. 2 саусақпен экранның төменгі жағынан жоғары қарай сырғытып, жылдам жіберіп қалыңыз."</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"Келесіде осы жылдам пәрменді қолданғанда, функция ашылады. 3 саусақпен экранның төменгі жағынан жоғары қарай сырғытып, жылдам жіберіп қалыңыз."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Ұлғайту"</string>
<string name="user_switched" msgid="7249833311585228097">"Ағымдағы пайдаланушы <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="1912993630661332336">"<xliff:g id="NAME">%1$s</xliff:g> профиліне ауысу…"</string>
@@ -2436,17 +2431,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Бұл қалай орындалады?"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Дайын емес…"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Саусақ ізімен ашу функциясын қайта реттеу"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> бұдан былай танылмайды."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> және <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> бұдан былай танылмайды."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"<xliff:g id="FINGERPRINT">%s</xliff:g> бұдан былай танылмайды. Саусақ ізімен ашу функциясын қайта реттеңіз."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> және <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> бұдан былай танылмайды. Саусақ ізімен ашу функциясын қайта реттеңіз."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"Бет тану функциясын қайта реттеу"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"Бет үлгіңіз бұдан былай танылмайды. Бет тану функциясын қайта реттеңіз."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Реттеу"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Қазір емес"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"<xliff:g id="USER_NAME">%s</xliff:g> атына қойылған дабыл"</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 88bf5274e48d..8fa4c58ffb91 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -265,8 +265,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"របាយការណ៍​កំហុស"</string>
<string name="global_action_logout" msgid="6093581310002476511">"បញ្ចប់​សម័យ"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"រូបថតអេក្រង់"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"របាយការណ៍អំពីបញ្ហា"</string>
<string name="bugreport_message" msgid="5212529146119624326">"វា​នឹង​​ប្រមូល​ព័ត៌មាន​អំពី​ស្ថានភាព​ឧបករណ៍​របស់​អ្នក ដើម្បី​ផ្ញើ​ជា​សារ​អ៊ីមែល។ វា​នឹង​ចំណាយ​ពេល​តិច​ពី​ពេល​ចាប់ផ្ដើម​របាយការណ៍​រហូត​ដល់​ពេល​វា​រួចរាល់​ដើម្បី​ផ្ញើ សូម​អត់ធ្មត់។"</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"របាយការណ៍អន្តរកម្ម"</string>
@@ -1767,12 +1765,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"មុខងារនេះនឹងបើក ពេលអ្នកចុចប៊ូតុង​ភាពងាយស្រួលនៅលើកក្រោយ"</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"មុខងារនេះនឹងបើក ពេលអ្នកប្រើផ្លូវកាត់នេះនៅលើកក្រោយ។ អូសពីផ្នែកខាងក្រោមនៃអេក្រង់របស់អ្នកឡើងលើដោយប្រើម្រាមដៃ 2 ហើយលែងឱ្យរហ័ស។"</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"មុខងារនេះនឹងបើក ពេលអ្នកប្រើផ្លូវកាត់នេះនៅលើកក្រោយ។ អូសពីផ្នែកខាងក្រោមនៃអេក្រង់របស់អ្នកឡើងលើដោយប្រើម្រាមដៃ 3 ហើយលែងឱ្យរហ័ស។"</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"ការ​ពង្រីក"</string>
<string name="user_switched" msgid="7249833311585228097">"អ្នក​ប្រើ​បច្ចុប្បន្ន <xliff:g id="NAME">%1$s</xliff:g> ។"</string>
<string name="user_switching_message" msgid="1912993630661332336">"កំពុង​ប្ដូរ​ទៅ <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2436,17 +2431,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"របៀបដែលវាដំណើរការ"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"កំពុងរង់ចាំ..."</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"រៀបចំការដោះសោ​ដោយស្កេន​ស្នាមម្រាមដៃម្ដងទៀត"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"លែងអាចសម្គាល់ <xliff:g id="FINGERPRINT">%s</xliff:g> បានទៀតហើយ។"</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"លែងអាចសម្គាល់ <xliff:g id="FINGERPRINT_0">%1$s</xliff:g> និង <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> បានទៀតហើយ។"</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"លែងអាចសម្គាល់ <xliff:g id="FINGERPRINT">%s</xliff:g> បានទៀតហើយ។ សូមរៀបចំការដោះសោ​ដោយស្កេន​ស្នាមម្រាមដៃម្ដងទៀត។"</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"លែងអាចសម្គាល់ <xliff:g id="FINGERPRINT_0">%1$s</xliff:g> និង <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> បានទៀតហើយ។ សូមរៀបចំការដោះសោ​ដោយស្កេន​ស្នាមម្រាមដៃម្ដងទៀត។"</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"រៀបចំ​ការដោះ​សោ​ដោយស្កេន​មុខម្ដងទៀត"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"លែងអាចសម្គាល់គំរូមុខរបស់អ្នកបានទៀតហើយ។ សូមរៀបចំ​ការដោះ​សោ​ដោយស្កេន​មុខម្ដងទៀត។"</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"រៀបចំ"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"កុំទាន់"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"ម៉ោងរោទ៍សម្រាប់ <xliff:g id="USER_NAME">%s</xliff:g>"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 59612451ddc0..dee9b4aecffe 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -265,8 +265,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"ದೋಷದ ವರದಿ"</string>
<string name="global_action_logout" msgid="6093581310002476511">"ಸೆಷನ್ ಅಂತ್ಯಗೊಳಿಸಿ"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"ಬಗ್ ವರದಿ"</string>
<string name="bugreport_message" msgid="5212529146119624326">"ನಿಮ್ಮ ಸಾಧನದ ಪ್ರಸ್ತುತ ಸ್ಥಿತಿಯ ಕುರಿತು ಮಾಹಿತಿಯನ್ನು ಸಂಗ್ರಹಿಸಿಕೊಳ್ಳುವುದರ ಜೊತೆ ಇ-ಮೇಲ್ ರೂಪದಲ್ಲಿ ನಿಮಗೆ ರವಾನಿಸುತ್ತದೆ. ಇದು ದೋಷ ವರದಿಯನ್ನು ಪ್ರಾರಂಭಿಸಿದ ಸಮಯದಿಂದ ಅದನ್ನು ಕಳುಹಿಸುವವರೆಗೆ ಸ್ವಲ್ಪ ಸಮಯವನ್ನು ತೆಗೆದುಕೊಳ್ಳುತ್ತದೆ; ದಯವಿಟ್ಟು ತಾಳ್ಮೆಯಿಂದಿರಿ."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"ಪರಸ್ಪರ ಸಂವಹನ ವರದಿ"</string>
@@ -2433,17 +2431,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"ಇದು ಹೇಗೆ ಕೆಲಸ ಮಾಡುತ್ತದೆ"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"ಬಾಕಿ ಉಳಿದಿದೆ..."</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"ಫಿಂಗರ್‌ಪ್ರಿಂಟ್ ಅನ್‌ಲಾಕ್ ಅನ್ನು ಮತ್ತೊಮ್ಮೆ ಸೆಟಪ್ ಮಾಡಿ"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> ಅನ್ನು ಇನ್ನು ಮುಂದೆ ಗುರುತಿಸಲಾಗುವುದಿಲ್ಲ."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> ಮತ್ತು <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> ಅನ್ನು ಇನ್ನು ಮುಂದೆ ಗುರುತಿಸಲಾಗುವುದಿಲ್ಲ."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"<xliff:g id="FINGERPRINT">%s</xliff:g> ಅನ್ನು ಇನ್ನು ಮುಂದೆ ಗುರುತಿಸಲಾಗುವುದಿಲ್ಲ. ಫಿಂಗರ್‌ಪ್ರಿಂಟ್ ಅನ್‌ಲಾಕ್ ಅನ್ನು ಮತ್ತೊಮ್ಮೆ ಸೆಟಪ್ ಮಾಡಿ."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> ಮತ್ತು <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> ಅನ್ನು ಇನ್ನು ಮುಂದೆ ಗುರುತಿಸಲಾಗುವುದಿಲ್ಲ. ಫಿಂಗರ್‌ಪ್ರಿಂಟ್ ಅನ್‌ಲಾಕ್ ಅನ್ನು ಮತ್ತೊಮ್ಮೆ ಸೆಟಪ್ ಮಾಡಿ."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"ಫೇಸ್ ಅನ್‌ಲಾಕ್ ಅನ್ನು ಮತ್ತೊಮ್ಮೆ ಸೆಟಪ್ ಮಾಡಿ"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"ನಿಮ್ಮ ಫೇಸ್ ಮಾಡೆಲ್ ಅನ್ನು ಇನ್ನು ಮುಂದೆ ಗುರುತಿಸಲಾಗುವುದಿಲ್ಲ. ಫೇಸ್ ಅನ್‌ಲಾಕ್ ಅನ್ನು ಮತ್ತೊಮ್ಮೆ ಸೆಟಪ್ ಮಾಡಿ."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"ಸೆಟಪ್ ಮಾಡಿ"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"ಈಗ ಬೇಡ"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"<xliff:g id="USER_NAME">%s</xliff:g> ಗಾಗಿ ಅಲಾರಾಂ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 1dea620e2bbc..7a4774b0377e 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -265,8 +265,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"버그 신고"</string>
<string name="global_action_logout" msgid="6093581310002476511">"세션 끝내기"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"스크린샷"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"버그 신고"</string>
<string name="bugreport_message" msgid="5212529146119624326">"현재 기기 상태에 대한 정보를 수집하여 이메일 메시지로 전송합니다. 버그 신고를 시작하여 전송할 준비가 되려면 약간 시간이 걸립니다."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"대화형 보고서"</string>
@@ -1199,7 +1197,7 @@
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"저장 공간이 부족함"</string>
<string name="low_internal_storage_view_text" msgid="8172166728369697835">"일부 시스템 기능이 작동하지 않을 수 있습니다."</string>
<string name="low_internal_storage_view_text_no_boot" msgid="7368968163411251788">"시스템의 저장 공간이 부족합니다. 250MB의 여유 공간이 확보한 후 다시 시작하세요."</string>
- <string name="app_running_notification_title" msgid="8985999749231486569">"<xliff:g id="APP_NAME">%1$s</xliff:g>이(가) 실행 중입니다."</string>
+ <string name="app_running_notification_title" msgid="8985999749231486569">"<xliff:g id="APP_NAME">%1$s</xliff:g> 실행 중"</string>
<string name="app_running_notification_text" msgid="5120815883400228566">"자세한 내용을 보거나 앱을 중지하려면 탭하세요."</string>
<string name="ok" msgid="2646370155170753815">"확인"</string>
<string name="cancel" msgid="6908697720451760115">"취소"</string>
@@ -1767,12 +1765,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"다음번에 접근성 버튼을 탭할 때 이 기능이 열립니다."</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"다음번에 이 단축키를 사용할 때 이 기능이 열립니다. 화면 하단에서 손가락 두 개를 사용해 위로 스와이프했다가 빠르게 놓습니다."</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"다음번에 이 단축키를 사용할 때 이 기능이 열립니다. 화면 하단에서 손가락 세 개를 사용해 위로 스와이프했다가 빠르게 놓습니다."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"확대"</string>
<string name="user_switched" msgid="7249833311585228097">"현재 사용자는 <xliff:g id="NAME">%1$s</xliff:g>님입니다."</string>
<string name="user_switching_message" msgid="1912993630661332336">"<xliff:g id="NAME">%1$s</xliff:g>로 전환하는 중…"</string>
@@ -2436,17 +2431,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"작동 방식"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"대기 중…"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"지문 잠금 해제 다시 설정"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> 지문을 더 이상 인식할 수 없습니다."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> 및 <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> 지문을 더 이상 인식할 수 없습니다."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"<xliff:g id="FINGERPRINT">%s</xliff:g> 지문을 더 이상 인식할 수 없습니다. 지문 잠금 해제를 다시 설정하세요."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> 및 <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> 지문을 더 이상 인식할 수 없습니다. 지문 잠금 해제를 다시 설정하세요."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"얼굴 인식 잠금 해제 다시 설정"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"얼굴 모델을 더 이상 인식할 수 없습니다. 얼굴 인식 잠금 해제를 다시 설정하세요."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"설정"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"나중에"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"<xliff:g id="USER_NAME">%s</xliff:g>님의 알람"</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index 47767936ae4b..cf1d2d349bc9 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -265,8 +265,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"Ката тууралуу билдирүү"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Сеансты бүтүрүү"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Скриншот"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"Мүчүлүштүк жөнүндө кабарлоо"</string>
<string name="bugreport_message" msgid="5212529146119624326">"Ушуну менен түзмөгүңүздүн учурдагы абалы тууралуу маалымат топтолуп, электрондук почта аркылуу жөнөтүлөт. Отчет даяр болгуча бир аз күтө туруңуз."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"Интерактивдүү кабар"</string>
@@ -1767,12 +1765,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"Эми функция атайын мүмкүнчүлүктөр баскычын басканыңызда ачылат"</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"Эми функция ушул ыкчам баскыч менен ачылат. Экранды 2 манжаңыз менен ылдыйдан өйдө карай сүрүп, тез коё бериңиз."</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"Эми функция ушул ыкчам баскыч менен ачылат. Экранды 3 манжаңыз менен ылдыйдан өйдө карай сүрүп, тез коё бериңиз."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Чоңойтуу"</string>
<string name="user_switched" msgid="7249833311585228097">"Учурдагы колдонуучу <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="1912993630661332336">"<xliff:g id="NAME">%1$s</xliff:g> дегенге которулууда…"</string>
@@ -2436,17 +2431,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Ал кантип иштейт"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Кезекте турат..."</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Манжа изи менен ачуу функциясын кайра тууралаңыз"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> мындан ары таанылбайт."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> жана <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> мындан ары таанылбайт."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"<xliff:g id="FINGERPRINT">%s</xliff:g> мындан ары таанылбайт. Манжа изи менен ачуу функциясын кайрадан тууралаңыз."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> жана <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> мындан ары таанылбайт. Манжа изи менен ачуу функциясын кайрадан тууралаңыз."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"Жүзүнөн таанып ачуу функциясын кайрадан тууралаңыз"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"Жүзүңүздүн үлгүсү мындан ары таанылбайт. Жүзүнөн таанып ачуу функциясын кайрадан тууралаңыз."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Тууралоо"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Азыр эмес"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"<xliff:g id="USER_NAME">%s</xliff:g> үчүн ойготкуч"</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 7e31a1ccbd1a..dde778bc73b0 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -265,8 +265,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"ລາຍງານຂໍ້ຜິດພາດ"</string>
<string name="global_action_logout" msgid="6093581310002476511">"ສິ້ນສຸດເຊດຊັນ"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"ພາບໜ້າຈໍ"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"ລາຍງານຂໍ້ຜິດພາດ"</string>
<string name="bugreport_message" msgid="5212529146119624326">"ນີ້ຈະເປັນການເກັບກຳຂໍ້ມູນກ່ຽວກັບ ສະຖານະປັດຈຸບັນຂອງອຸປະກອນທ່ານ ເພື່ອສົ່ງເປັນຂໍ້ຄວາມທາງອີເມວ. ມັນຈະໃຊ້ເວລາໜ້ອຍນຶ່ງ ໃນການເລີ່ມຕົ້ນການລາຍງານຂໍ້ຜິດພາດ ຈົນກວ່າຈະພ້ອມທີ່ຈະສົ່ງໄດ້, ກະລຸນາລໍຖ້າ."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"ລາຍງານແບບໂຕ້ຕອບ"</string>
@@ -1767,12 +1765,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"ຄຸນສົມບັດນີ້ຈະເປີດຂຶ້ນໃນເທື່ອຕໍ່ໄປທີ່ທ່ານແຕະປຸ່ມການຊ່ວຍເຂົ້າເຖິງ"</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"ຄຸນສົມບັດນີ້ຈະເປີດຂຶ້ນໃນເທື່ອຕໍ່ໄປທີ່ທ່ານໃຊ້ທາງລັດນີ້. ໃຊ້ 2 ນິ້ວປັດຂຶ້ນຈາກລຸ່ມສຸດຂອງໜ້າຈໍຂອງທ່ານແລ້ວປ່ອຍແບບໄວໆ."</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"ຄຸນສົມບັດນີ້ຈະເປີດຂຶ້ນໃນເທື່ອຕໍ່ໄປທີ່ທ່ານໃຊ້ທາງລັດນີ້. ໃຊ້ 3 ນິ້ວປັດຂຶ້ນຈາກລຸ່ມສຸດຂອງໜ້າຈໍຂອງທ່ານແລ້ວປ່ອຍແບບໄວໆ."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"ການຂະຫຍາຍ"</string>
<string name="user_switched" msgid="7249833311585228097">"ຜູ່ໃຊ້ປັດຈຸບັນ <xliff:g id="NAME">%1$s</xliff:g> ."</string>
<string name="user_switching_message" msgid="1912993630661332336">"ກຳລັງສະຫຼັບໄປຫາ<xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2436,17 +2431,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"ມັນເຮັດວຽກແນວໃດ"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"ລໍຖ້າດຳເນີນການ..."</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"ຕັ້ງຄ່າການປົດລັອກດ້ວຍລາຍນິ້ວມືຄືນໃໝ່"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"ບໍ່ສາມາດຈຳແນກ <xliff:g id="FINGERPRINT">%s</xliff:g> ໄດ້ອີກຕໍ່ໄປ."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"ບໍ່ສາມາດຈຳແນກ <xliff:g id="FINGERPRINT_0">%1$s</xliff:g> ແລະ <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> ໄດ້ອີກຕໍ່ໄປ."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"ບໍ່ສາມາດຈຳແນກ <xliff:g id="FINGERPRINT">%s</xliff:g> ໄດ້ອີກຕໍ່ໄປ. ກະລຸນາຕັ້ງຄ່າການປົດລັອກດ້ວຍລາຍນິ້ວມືອີກຄັ້ງ."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"ບໍ່ສາມາດຈຳແນກ <xliff:g id="FINGERPRINT_0">%1$s</xliff:g> ແລະ <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> ໄດ້ອີກຕໍ່ໄປ. ກະລຸນາຕັ້ງຄ່າການປົດລັອກດ້ວຍລາຍນິ້ວມືອີກຄັ້ງ."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"ຕັ້ງຄ່າການປົດລັອກດ້ວຍໜ້າຄືນໃໝ່"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"ບໍ່ສາມາດຈຳແນກຮູບແບບໃບໜ້າຂອງທ່ານໄດ້ອີກຕໍ່ໄປ. ກະລຸນາຕັ້ງຄ່າການປົດລັອກດ້ວຍໜ້າອີກຄັ້ງ."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"ຕັ້ງຄ່າ"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"ບໍ່ຟ້າວເທື່ອ"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"ໂມງປຸກສຳລັບ <xliff:g id="USER_NAME">%s</xliff:g>"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 87027a68770d..f7ee53aaaf7e 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -267,8 +267,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"Pranešimas apie riktą"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Baigti seansą"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Ekrano kopija"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"Pranešim. apie riktą"</string>
<string name="bugreport_message" msgid="5212529146119624326">"Bus surinkta informacija apie dabartinę įrenginio būseną ir išsiųsta el. pašto pranešimu. Šiek tiek užtruks, kol pranešimas apie riktą bus paruoštas siųsti; būkite kantrūs."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"Interakt. ataskaita"</string>
@@ -1769,12 +1767,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"Funkcija bus atidaryta kitą kartą, kai paliesite pritaikomumo mygtuką"</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"Funkcija bus atidaryta kitą kartą, kai naudosite šį spartųjį klavišą. Perbraukite dviem pirštais aukštyn nuo ekrano apačios ir greitai atleiskite."</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"Funkcija bus atidaryta kitą kartą, kai naudosite šį spartųjį klavišą. Perbraukite trimis pirštais aukštyn nuo ekrano apačios ir greitai atleiskite."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Didinimas"</string>
<string name="user_switched" msgid="7249833311585228097">"Dabartinis naudotojas: <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="1912993630661332336">"Perjungiama į <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2438,17 +2433,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Kaip tai veikia"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Laukiama..."</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Atrakinimo piršto atspaudu nustatymas dar kartą"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> nebegalima atpažinti."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> ir <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> nebegalima atpažinti."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"<xliff:g id="FINGERPRINT">%s</xliff:g> nebegalima atpažinti. Dar kartą nustatykite atrakinimą piršto atspaudu."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> ir <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> nebegalima atpažinti. Dar kartą nustatykite atrakinimą piršto atspaudu."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"Atrakinimo pagal veidą nustatymas iš naujo"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"Jūsų veido modelio nebegalima atpažinti. Iš naujo nustatykite atrakinimą pagal veidą."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Nustatyti"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Ne dabar"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"Signalas: <xliff:g id="USER_NAME">%s</xliff:g>"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 3bd986ef12b2..6cc99a453e31 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -266,8 +266,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"Kļūdu ziņojums"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Beigt sesiju"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Ekrānuzņēmums"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"Kļūdas pārskats"</string>
<string name="bugreport_message" msgid="5212529146119624326">"Veicot šo darbību, tiks apkopota informācija par jūsu ierīces pašreizējo stāvokli un nosūtīta e-pasta ziņojuma veidā. Kļūdu ziņojuma pabeigšanai un nosūtīšanai var būt nepieciešams laiks. Lūdzu, esiet pacietīgs."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"Interaktīvs pārskats"</string>
@@ -1768,12 +1766,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"Funkcija tiks atvērta, kad nākamreiz pieskarsieties pieejamības pogai."</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"Funkcija tiks atvērta, kad nākamreiz izmantosiet šo saīsni. Velciet augšup ar diviem pirkstiem no ekrāna apakšdaļas un ātri atlaidiet."</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"Funkcija tiks atvērta, kad nākamreiz izmantosiet šo saīsni. Velciet augšup ar trim pirkstiem no ekrāna apakšdaļas un ātri atlaidiet."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Palielinājums"</string>
<string name="user_switched" msgid="7249833311585228097">"Pašreizējais lietotājs: <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="1912993630661332336">"Notiek pāriešana uz: <xliff:g id="NAME">%1$s</xliff:g>"</string>
@@ -2437,17 +2432,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Darbības principi"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Gaida…"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Vēlreiz iestatiet autorizāciju ar pirksta nospiedumu"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"Pirksta nospiedumu (<xliff:g id="FINGERPRINT">%s</xliff:g>) vairs nevar atpazīt."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"Pirkstu nospiedumus (<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> un <xliff:g id="FINGERPRINT_1">%2$s</xliff:g>) vairs nevar atpazīt."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"Pirksta nospiedumu (<xliff:g id="FINGERPRINT">%s</xliff:g>) vairs nevar atpazīt. Vēlreiz iestatiet autorizāciju ar pirksta nospiedumu."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"Pirkstu nospiedumus (<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> un <xliff:g id="FINGERPRINT_1">%2$s</xliff:g>) vairs nevar atpazīt. Vēlreiz iestatiet autorizāciju ar pirksta nospiedumu."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"Vēlreiz iestatiet autorizāciju pēc sejas"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"Jūsu sejas modeli vairs nevar atpazīt. Vēlreiz iestatiet autorizāciju pēc sejas."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Iestatīt"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Ne tagad"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"Signāls lietotājam <xliff:g id="USER_NAME">%s</xliff:g>"</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index afcf2d5d8b6c..cf70e96b0cac 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -265,8 +265,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"Извештај за грешка"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Завршете ја сесијата"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Слика од екранот"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"Извештај за грешки"</string>
<string name="bugreport_message" msgid="5212529146119624326">"Ова ќе собира информации за моменталната состојба на вашиот уред, за да ги испрати како порака по е-пошта. Тоа ќе одземе малку време почнувајќи од извештајот за грешки додека не се подготви за праќање; бидете трпеливи."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"Интерактивен извештај"</string>
@@ -1767,12 +1765,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"Функцијата ќе се отвори следниот пат кога ќе го допрете копчето за пристапност"</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"Функцијата ќе се отвори следниот пат кога ќе ја користите кратенкава. Повлечете нагоре со 2 прста од долниот дел на екранот и брзо отпуштете."</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"Функцијата ќе се отвори следниот пат кога ќе ја користите кратенкава. Повлечете нагоре со 3 прста од долниот дел на екранот и брзо отпуштете."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Зголемување"</string>
<string name="user_switched" msgid="7249833311585228097">"Тековен корисник <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="1912993630661332336">"Се префрла на <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2436,17 +2431,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Дознајте како функционира"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Во фаза на чекање…"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Поставете „Отклучување со отпечаток“ повторно"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> веќе не може да се препознае."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> и <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> веќе не може да се препознаат."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"<xliff:g id="FINGERPRINT">%s</xliff:g> веќе не може да се препознае. Поставете „Отклучување со отпечаток“ повторно."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> и <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> веќе не може да се препознаат. Поставете „Отклучување со отпечаток“ повторно."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"Поставете „Отклучување со лик“ повторно"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"Вашиот модел на лик веќе не може да се препознае. Поставете „Отклучување со лик“ повторно."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Поставете"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Не сега"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"Аларм за <xliff:g id="USER_NAME">%s</xliff:g>"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index 7cac60a7dee5..f13f1bbde16a 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -265,8 +265,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"ബഗ് റിപ്പോർട്ട്"</string>
<string name="global_action_logout" msgid="6093581310002476511">"സെഷൻ അവസാനിപ്പിക്കുക"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"സ്‌ക്രീൻഷോട്ട്"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"ബഗ് റിപ്പോർട്ട്"</string>
<string name="bugreport_message" msgid="5212529146119624326">"ഒരു ഇമെയിൽ സന്ദേശമായി അയയ്‌ക്കുന്നതിന്, ഇത് നിങ്ങളുടെ നിലവിലെ ഉപകരണ നിലയെക്കുറിച്ചുള്ള വിവരങ്ങൾ ശേഖരിക്കും. ബഗ് റിപ്പോർട്ട് ആരംഭിക്കുന്നതിൽ നിന്ന് ഇത് അയയ്‌ക്കാനായി തയ്യാറാകുന്നതുവരെ അൽപ്പസമയമെടുക്കും; ക്ഷമയോടെ കാത്തിരിക്കുക."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"ഇന്റരാക്റ്റീവ് റിപ്പോർട്ട്"</string>
@@ -1767,12 +1765,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"അടുത്ത തവണ നിങ്ങൾ ഉപയോഗസഹായി ബട്ടൺ ടാപ്പ് ചെയ്യുമ്പോൾ ഫീച്ചർ തുറക്കും"</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"അടുത്ത തവണ നിങ്ങൾ ഈ കുറുക്കുവഴി ഉപയോഗിക്കുമ്പോൾ ഫീച്ചർ തുറക്കും. നിങ്ങളുടെ സ്ക്രീനിന്റെ താഴെ നിന്ന് 2 വിരലുകൾ ഉപയോഗിച്ച് മുകളിലേക്ക് സ്വൈപ്പ് ചെയ്‌ത് പെട്ടെന്ന് വിടുക."</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"അടുത്ത തവണ നിങ്ങൾ ഈ കുറുക്കുവഴി ഉപയോഗിക്കുമ്പോൾ ഫീച്ചർ തുറക്കും. നിങ്ങളുടെ സ്ക്രീനിന്റെ താഴെ നിന്ന് 3 വിരലുകൾ ഉപയോഗിച്ച് മുകളിലേക്ക് സ്വൈപ്പ് ചെയ്‌ത് പെട്ടെന്ന് വിടുക."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"മാഗ്നിഫിക്കേഷൻ"</string>
<string name="user_switched" msgid="7249833311585228097">"നിലവിലെ ഉപയോക്താവ് <xliff:g id="NAME">%1$s</xliff:g> ആണ്."</string>
<string name="user_switching_message" msgid="1912993630661332336">"<xliff:g id="NAME">%1$s</xliff:g> എന്ന ഉപയോക്താവിലേക്ക് മാറുന്നു…"</string>
@@ -2436,17 +2431,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"ഇത് പ്രവർത്തിക്കുന്നത് എങ്ങനെയാണ്"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"തീർപ്പാക്കിയിട്ടില്ല..."</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"ഫിംഗർപ്രിന്റ് അൺലോക്ക് വീണ്ടും സജ്ജീകരിക്കുക"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> ഇനി തിരിച്ചറിയാനാകില്ല."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g>, <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> എന്നിവ ഇനി തിരിച്ചറിയാനാകില്ല."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"<xliff:g id="FINGERPRINT">%s</xliff:g> ഇനി തിരിച്ചറിയാനാകില്ല. ഫിംഗർപ്രിന്റ് അൺലോക്ക് വീണ്ടും സജ്ജീകരിക്കുക."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g>, <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> എന്നിവ ഇനി തിരിച്ചറിയാനാകില്ല. ഫിംഗർപ്രിന്റ് അൺലോക്ക് വീണ്ടും സജ്ജീകരിക്കുക."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"ഫെയ്‌സ് അൺലോക്ക് വീണ്ടും സജ്ജീകരിക്കുക"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"നിങ്ങളുടെ മുഖ മോഡൽ ഇനി തിരിച്ചറിയാനാകില്ല. ഫെയ്‌സ് അൺലോക്ക് വീണ്ടും സജ്ജീകരിക്കുക."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"സജ്ജീകരിക്കുക"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"ഇപ്പോൾ വേണ്ട"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"<xliff:g id="USER_NAME">%s</xliff:g> എന്നയാൾക്കുള്ള അലാറം"</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 7a2fa5390909..109cce8f9b35 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -265,8 +265,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"Алдаа мэдээлэх"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Гаргах харилцан үйлдэл"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Дэлгэцийн зураг дарах"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"Алдааны мэдээ"</string>
<string name="bugreport_message" msgid="5212529146119624326">"Энэ таны төхөөрөмжийн одоогийн статусын талаарх мэдээллийг цуглуулах ба имэйл мессеж болгон илгээнэ. Алдааны мэдэгдлээс эхэлж илгээхэд бэлэн болоход хэсэг хугацаа зарцуулагдана тэвчээртэй байна уу."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"Интерактив тайлан"</string>
@@ -1767,12 +1765,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"Таныг дараагийн удаа хандалтын товчийг товших үед тус онцлог нээгдэнэ"</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"Таныг дараагийн удаа энэ товчлолыг ашиглах үед тус онцлог нээгдэнэ. Дэлгэцийнхээ доод талаас 2 хуруугаараа дээш шудраад, түргэн суллана уу."</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"Таныг дараагийн удаа энэ товчлолыг ашиглах үед тус онцлог нээгдэнэ. Дэлгэцийнхээ доод талаас 3 хуруугаараа дээш шудраад, түргэн суллана уу."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Томруулах"</string>
<string name="user_switched" msgid="7249833311585228097">"Одоогийн хэрэглэгч <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="1912993630661332336">"<xliff:g id="NAME">%1$s</xliff:g> руу сэлгэж байна…"</string>
@@ -2436,17 +2431,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Энэ хэрхэн ажилладаг вэ?"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Хүлээгдэж буй..."</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Хурууны хээгээр түгжээ тайлахыг дахин тохируулна уу"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g>-г цаашид таних боломжгүй."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> болон <xliff:g id="FINGERPRINT_1">%2$s</xliff:g>-г цаашид таних боломжгүй."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"<xliff:g id="FINGERPRINT">%s</xliff:g>-г цаашид таних боломжгүй. Хурууны хээгээр түгжээ тайлахыг дахин тохируулна уу."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> болон <xliff:g id="FINGERPRINT_1">%2$s</xliff:g>-г цаашид таних боломжгүй. Хурууны хээгээр түгжээ тайлахыг дахин тохируулна уу."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"Царайгаар түгжээ тайлахыг дахин тохируулна уу"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"Таны нүүрний загварыг цаашид таних боломжгүй. Царайгаар түгжээ тайлахыг дахин тохируулна уу."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Тохируулах"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Одоо биш"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"<xliff:g id="USER_NAME">%s</xliff:g>-н сэрүүлэг"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index f811004ae520..3817d27fda57 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -265,8 +265,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"बग रिपोर्ट"</string>
<string name="global_action_logout" msgid="6093581310002476511">"सेशन समाप्त करा"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"स्क्रीनशॉट"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"बग रिपोर्ट"</string>
<string name="bugreport_message" msgid="5212529146119624326">"ईमेल मेसेज म्हणून पाठविण्यासाठी, हे तुमच्या सध्याच्या डिव्हाइस स्थितीविषयी माहिती संकलित करेल. बग रिपोर्ट सुरू करण्यापासून तो पाठवण्यापर्यंत थोडा वेळ लागेल; कृपया धीर धरा."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"परस्परसंवादी अहवाल"</string>
@@ -2433,17 +2431,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"ते कसे काम करते"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"प्रलंबित आहे..."</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"फिंगरप्रिंट अनलॉक पुन्हा सेट करा"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> यापुढे ओळखता येणार नाही."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> आणि <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> यापुढे ओळखता येणार नाहीत."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"<xliff:g id="FINGERPRINT">%s</xliff:g> यापुढे ओळखता येणार नाही. फिंगरप्रिंट अनलॉक पुन्हा सेट करा."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> आणि <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> यापुढे ओळखता येणार नाहीत. फिंगरप्रिंट अनलॉक पुन्हा सेट करा."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"फेस अनलॉक पुन्हा सेट करा"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"तुमचे फेस मॉडेल यापुढे ओळखता येणार नाही. फेस अनलॉक पुन्हा सेट करा."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"सेट करा"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"आताच नको"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"<xliff:g id="USER_NAME">%s</xliff:g> साठी अलार्म"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 0bd939ec0759..d1bd23d48535 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -265,8 +265,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"Laporan pepijat"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Tamatkan sesi"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Tangkapan skrin"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"Laporan pepijat"</string>
<string name="bugreport_message" msgid="5212529146119624326">"Ini akan mengumpul maklumat tentang keadaan peranti semasa anda untuk dihantarkan sebagai mesej e-mel. Harap bersabar, mungkin perlu sedikit masa untuk memulakan laporan sehingga siap untuk dihantar."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"Laporan interaktif"</string>
@@ -1442,7 +1440,7 @@
<string name="alert_windows_notification_channel_group_name" msgid="6063891141815714246">"Paparkan di atas apl lain"</string>
<string name="alert_windows_notification_channel_name" msgid="3437528564303192620">"<xliff:g id="NAME">%s</xliff:g> dipaparkan di atas apl lain"</string>
<string name="alert_windows_notification_title" msgid="6331662751095228536">"<xliff:g id="NAME">%s</xliff:g> dipaparkan di atas apl lain"</string>
- <string name="alert_windows_notification_message" msgid="6538171456970725333">"Jika anda tidak mahu <xliff:g id="NAME">%s</xliff:g> menggunakan ciri ini, ketik untuk membuka tetapan dan matikannya."</string>
+ <string name="alert_windows_notification_message" msgid="6538171456970725333">"Jika anda tidak mahu <xliff:g id="NAME">%s</xliff:g> menggunakan ciri ini, ketik untuk membuka tetapan dan matikan ciri tersebut."</string>
<string name="alert_windows_notification_turn_off_action" msgid="7805857234839123780">"Matikan"</string>
<string name="ext_media_checking_notification_title" msgid="8299199995416510094">"Menyemak <xliff:g id="NAME">%s</xliff:g>…"</string>
<string name="ext_media_checking_notification_message" msgid="2231566971425375542">"Menyemak kandungan semasa"</string>
@@ -2433,17 +2431,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Cara ciri ini berfungsi"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Belum selesai..."</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Sediakan Buka Kunci Cap Jari sekali lagi"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> tidak dapat dicam lagi."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> dan <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> tidak dapat dicam lagi."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"<xliff:g id="FINGERPRINT">%s</xliff:g> tidak dapat dicam lagi. Sediakan semula Buka Kunci Cap Jari."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> dan <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> tidak dapat dicam lagi. Sediakan semula Buka Kunci Cap Jari."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"Sediakan semula Buka Kunci Wajah"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"Model wajah anda tidak dapat dicam lagi. Sediakan semula Buka Kunci Wajah."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Sediakan"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Bukan sekarang"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"Penggera untuk <xliff:g id="USER_NAME">%s</xliff:g>"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 29efeedbbf95..535b8545b9fd 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -265,8 +265,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"အမှားရှာပြင် မှတ်တမ်း"</string>
<string name="global_action_logout" msgid="6093581310002476511">"စက်ရှင် ပြီးဆုံးပြီ"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"ဖန်သားပြင်ဓာတ်ပုံ"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"ချွတ်ယွင်းချက်အစီရင်ခံစာ"</string>
<string name="bugreport_message" msgid="5212529146119624326">"သင့်ရဲ့ လက်ရှိ စက်အခြေအနေ အချက်အလက်များကို အီးမေးလ် အနေဖြင့် ပေးပို့ရန် စုဆောင်းပါမည်။ အမှားရှာဖွေပြင်ဆင်မှုမှတ်တမ်းမှ ပေးပို့ရန် အသင့်ဖြစ်သည်အထိ အချိန် အနည်းငယ်ကြာမြင့်မှာ ဖြစ်သဖြင့် သည်းခံပြီး စောင့်ပါရန်"</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"လက်ငင်းတုံ့ပြန်နိုင်သည့် အစီရင်ခံချက်"</string>
@@ -2433,17 +2431,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"အလုပ်လုပ်ပုံ"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"ဆိုင်းငံ့ထားသည်…"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"‘လက်ဗွေသုံး လော့ခ်ဖွင့်ခြင်း’ ကို စနစ်ထပ်မံထည့်သွင်းပါ"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> ကို မသိရှိနိုင်တော့ပါ။"</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> နှင့် <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> ကို မသိရှိနိုင်တော့ပါ။"</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"<xliff:g id="FINGERPRINT">%s</xliff:g> ကို မသိရှိနိုင်တော့ပါ။ ‘လက်ဗွေသုံး လော့ခ်ဖွင့်ခြင်း’ ထပ်မံစနစ်ထည့်သွင်းပါ။"</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> နှင့် <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> ကို မသိရှိနိုင်တော့ပါ။ ‘လက်ဗွေသုံး လော့ခ်ဖွင့်ခြင်း’ ထပ်မံစနစ်ထည့်သွင်းပါ။"</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"‘မျက်နှာပြ လော့ခ်ဖွင့်ခြင်း’ ကို စနစ်ထပ်မံထည့်သွင်းပါ"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"သင်၏မျက်နှာနမူနာကို မသိရှိနိုင်တော့ပါ။ ‘မျက်နှာပြ လော့ခ်ဖွင့်ခြင်း’ ထပ်မံစနစ်ထည့်သွင်းပါ။"</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"စနစ်ထည့်သွင်းရန်"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"ယခုမလုပ်ပါ"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"<xliff:g id="USER_NAME">%s</xliff:g> အတွက် နှိုးစက်"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index e60f43f0c0d8..fe45ab738290 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -264,9 +264,7 @@
<string name="global_action_emergency" msgid="1387617624177105088">"Nødssituasjon"</string>
<string name="global_action_bug_report" msgid="5127867163044170003">"Feilrapport"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Avslutt økten"</string>
- <string name="global_action_screenshot" msgid="2610053466156478564">"Skjermdump"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
+ <string name="global_action_screenshot" msgid="2610053466156478564">"Skjermbilde"</string>
<string name="bugreport_title" msgid="8549990811777373050">"Feilrapport"</string>
<string name="bugreport_message" msgid="5212529146119624326">"Informasjon om tilstanden til enheten din samles inn og sendes som en e-post. Det tar litt tid fra du starter feilrapporten til e-posten er klar, så vær tålmodig."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"Interaktiv rapport"</string>
@@ -1767,12 +1765,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"Funksjonen åpnes neste gang du trykker på Tilgjengelighet-knappen"</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"Funksjonen åpnes neste gang du bruker denne snarveien. Sveip opp med 2 fingre fra nederst på skjermen, og slipp raskt opp."</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"Funksjonen åpnes neste gang du bruker denne snarveien. Sveip opp med 3 fingre fra nederst på skjermen, og slipp raskt opp."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Forstørring"</string>
<string name="user_switched" msgid="7249833311585228097">"Gjeldende bruker: <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="1912993630661332336">"Bytter til <xliff:g id="NAME">%1$s</xliff:g> …"</string>
@@ -2202,7 +2197,7 @@
<string name="accessibility_system_action_quick_settings_label" msgid="4583900123506773783">"Hurtiginnstillinger"</string>
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Dialogboks for å slå av/på"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Låseskjerm"</string>
- <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Skjermdump"</string>
+ <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Skjermbilde"</string>
<string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"Hook for hodetelefoner"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Tilgjengelighetssnarvei på skjermen"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Velger for tilgjengelighetssnarvei på skjermen"</string>
@@ -2436,17 +2431,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Slik fungerer det"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Venter …"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Konfigurer opplåsingen med fingeravtrykk på nytt"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> gjenkjennes ikke lenger."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> og <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> gjenkjennes ikke lenger."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"<xliff:g id="FINGERPRINT">%s</xliff:g> gjenkjennes ikke lenger. Konfigurer opplåsing med fingeravtrykk på nytt."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> og <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> gjenkjennes ikke lenger. Konfigurer opplåsing med fingeravtrykk på nytt."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"Konfigurer ansiktslåsen på nytt"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"Ansiktsmodellen din gjenkjennes ikke lenger. Konfigurer ansiktslåsen på nytt."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Konfigurer"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Ikke nå"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"Alarm for <xliff:g id="USER_NAME">%s</xliff:g>"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index dee68258119d..8519e235a369 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -265,8 +265,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"बग रिपोर्ट"</string>
<string name="global_action_logout" msgid="6093581310002476511">"सत्रको अन्त्य गर्नुहोस्"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"स्क्रिनसट"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"बग रिपोर्ट"</string>
<string name="bugreport_message" msgid="5212529146119624326">"एउटा इमेल सन्देशको रूपमा पठाउनलाई यसले तपाईँको हालैको उपकरणको अवस्थाको बारेमा सूचना जम्मा गर्ने छ। बग रिपोर्ट सुरु गरेदेखि पठाउन तयार नभएसम्म यसले केही समय लिन्छ; कृपया धैर्य गर्नुहोस्।"</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"अन्तरक्रियामूलक रिपोर्ट"</string>
@@ -2433,17 +2431,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"यसले काम गर्ने तरिका"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"विचाराधीन..."</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"फिंगरप्रिन्ट अनलक फेरि सेटअप गर्नुहोस्"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> अब पहिचान गर्न सकिँदैन।"</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> र <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> अब पहिचान गर्न सकिँदैन।"</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"<xliff:g id="FINGERPRINT">%s</xliff:g> अब पहिचान गर्न सकिँदैन। फिंगरप्रिन्ट अनलक फेरि सेटअप गर्नुहोस्।"</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> र <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> अब पहिचान गर्न सकिँदैन। फिंगरप्रिन्ट अनलक फेरि सेटअप गर्नुहोस्।"</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"फेस अनलक फेरि सेटअप गर्नुहोस्"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"तपाईंको फेस मोडेल अब पहिचान गर्न सकिँदैन। फेस अनलक फेरि सेटअप गर्नुहोस्।"</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"सेटअप गर्नुहोस्"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"अहिले होइन"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"<xliff:g id="USER_NAME">%s</xliff:g> का निम्ति अलार्म"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 7bb69276ad10..e557d5993e60 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -265,8 +265,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"Bugrapport"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Sessie beëindigen"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Screenshot"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"Bugrapport"</string>
<string name="bugreport_message" msgid="5212529146119624326">"Hiermee worden gegevens over de huidige status van je apparaat verzameld en als e-mail verzonden. Wanneer u een bugrapport start, duurt het even voordat het kan worden verzonden. Even geduld alstublieft."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"Interactief rapport"</string>
@@ -1767,12 +1765,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"De functie opent de volgende keer dat je op de knop Toegankelijkheid tikt"</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"De functie opent de volgende keer dat je deze snelkoppeling gebruikt. Swipe met 2 vingers omhoog vanaf de onderkant van je scherm en laat snel los."</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"De functie opent de volgende keer dat je deze snelkoppeling gebruikt. Swipe met 3 vingers omhoog vanaf de onderkant van je scherm en laat snel los."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Vergroting"</string>
<string name="user_switched" msgid="7249833311585228097">"Huidige gebruiker <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="1912993630661332336">"Overschakelen naar <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2436,17 +2431,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Hoe het werkt"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"In behandeling…"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Ontgrendelen met vingerafdruk weer instellen"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> wordt niet meer herkend."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> en <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> worden niet meer herkend."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"<xliff:g id="FINGERPRINT">%s</xliff:g> wordt niet meer herkend. Stel Ontgrendelen met vingerafdruk opnieuw in."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> en <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> worden niet meer herkend. Stel Ontgrendelen met vingerafdruk opnieuw in."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"Ontgrendelen via gezichtsherkenning weer instellen"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"Je gezichtsmodel wordt niet meer herkend. Stel Ontgrendelen via gezichtsherkenning opnieuw in."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Instellen"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Niet nu"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"Wekker voor <xliff:g id="USER_NAME">%s</xliff:g>"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index 1c6d1917ec2b..211d0aec165d 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -265,8 +265,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"ବଗ୍‌ ରିପୋର୍ଟ"</string>
<string name="global_action_logout" msgid="6093581310002476511">"ସେସନ୍‍ ଶେଷ କରନ୍ତୁ"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"ସ୍କ୍ରିନସଟ"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"ବଗ୍‌ ରିପୋର୍ଟ"</string>
<string name="bugreport_message" msgid="5212529146119624326">"ଇ-ମେଲ୍ ମେସେଜ୍‍ ଭାବରେ ପଠାଇବାକୁ, ଆପଣଙ୍କ ବର୍ତ୍ତମାନର ଡିଭାଇସ୍‌ ବିଷୟରେ ଏହା ସୂଚନା ସଂଗ୍ରହ କରିବ। ବଗ୍ ରିପୋର୍ଟ ଆରମ୍ଭ ହେବାପରଠାରୁ ଏହାକୁ ପଠାଇବା ପାଇଁ କିଛି ସମୟ ଲାଗିବ, ଦୟାକରି ଧୈର୍ଯ୍ୟ ରଖନ୍ତୁ।"</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"ଇଣ୍ଟରାକ୍ଟିଭ୍‍ ରିପୋର୍ଟ"</string>
@@ -1767,12 +1765,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"ଆପଣ ଆଗାମୀ ଥର ଆକ୍ସେସିବିଲିଟୀ ବଟନରେ ଟାପ କଲେ ଏହି ଫିଚରଟି ଖୋଲିବ"</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"ଆପଣ ଆଗାମୀ ଥର ଏହି ସର୍ଟକଟକୁ ବ୍ୟବହାର କଲେ ଏହି ଫିଚରଟି ଖୋଲିବ। ଆପଣଙ୍କ ସ୍କ୍ରିନର ନିମ୍ନଭାଗରୁ 2 ଆଙ୍ଗୁଠିରେ ଉପରକୁ ସ୍ୱାଇପ କରି ଶୀଘ୍ର ରିଲିଜ କରନ୍ତୁ।"</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"ଆପଣ ଆଗାମୀ ଥର ଏହି ସର୍ଟକଟକୁ ବ୍ୟବହାର କଲେ ଏହି ଫିଚରଟି ଖୋଲିବ। ଆପଣଙ୍କ ସ୍କ୍ରିନର ନିମ୍ନଭାଗରୁ 3 ଆଙ୍ଗୁଠିରେ ଉପରକୁ ସ୍ୱାଇପ କରି ଶୀଘ୍ର ରିଲିଜ କରନ୍ତୁ।"</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"ମେଗ୍ନିଫିକେସନ"</string>
<string name="user_switched" msgid="7249833311585228097">"ବର୍ତ୍ତମାନର ୟୁଜର୍‌ ହେଉଛନ୍ତି <xliff:g id="NAME">%1$s</xliff:g>।"</string>
<string name="user_switching_message" msgid="1912993630661332336">"<xliff:g id="NAME">%1$s</xliff:g>ରେ ସ୍ୱିଚ କରନ୍ତୁ…"</string>
@@ -2436,17 +2431,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"ଏହା କିପରି କାମ କରେ"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"ବାକି ଅଛି…"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"ଫିଙ୍ଗରପ୍ରିଣ୍ଟ ଅନଲକ ପୁଣି ସେଟ ଅପ କରନ୍ତୁ"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g>କୁ ଆଉ ଚିହ୍ନଟ କରାଯାଇପାରିବ ନାହିଁ।"</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> ଏବଂ <xliff:g id="FINGERPRINT_1">%2$s</xliff:g>କୁ ଆଉ ଚିହ୍ନଟ କରାଯାଇପାରିବ ନାହିଁ।"</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"<xliff:g id="FINGERPRINT">%s</xliff:g>କୁ ଆଉ ଚିହ୍ନଟ କରାଯାଇପାରିବ ନାହିଁ। ଫିଙ୍ଗରପ୍ରିଣ୍ଟ ଅନଲକ ପୁଣି ସେଟ ଅପ କରନ୍ତୁ।"</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> ଏବଂ <xliff:g id="FINGERPRINT_1">%2$s</xliff:g>କୁ ଆଉ ଚିହ୍ନଟ କରାଯାଇପାରିବ ନାହିଁ। ଫିଙ୍ଗରପ୍ରିଣ୍ଟ ଅନଲକ ପୁଣି ସେଟ ଅପ କରନ୍ତୁ।"</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"ଫେସ୍ ଅନଲକ୍ ପୁଣି ସେଟ୍ ଅପ୍ କରନ୍ତୁ"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"ଆପଣଙ୍କ ଫେସ ମଡେଲକୁ ଆଉ ଚିହ୍ନଟ କରାଯାଇପାରିବ ନାହିଁ। ଫେସ ଅନଲକ ପୁଣି ସେଟ ଅପ କରନ୍ତୁ।"</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"ସେଟ ଅପ କରନ୍ତୁ"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"ବର୍ତ୍ତମାନ ନୁହେଁ"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"<xliff:g id="USER_NAME">%s</xliff:g>ଙ୍କ ପାଇଁ ଆଲାରାମ"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 996f25595a5e..76ddb421e518 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -265,8 +265,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"ਬਗ ਰਿਪੋਰਟ"</string>
<string name="global_action_logout" msgid="6093581310002476511">"ਸੈਸ਼ਨ ਸਮਾਪਤ ਕਰੋ"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਲਵੋ"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"ਬੱਗ ਰਿਪੋਰਟ"</string>
<string name="bugreport_message" msgid="5212529146119624326">"ਇਹ ਇੱਕ ਈਮੇਲ ਸੁਨੇਹਾ ਭੇਜਣ ਲਈ, ਤੁਹਾਡੇ ਵਰਤਮਾਨ ਡੀਵਾਈਸ ਬਾਰੇ ਜਾਣਕਾਰੀ ਇਕੱਠੀ ਕਰੇਗਾ। ਬੱਗ ਰਿਪੋਰਟ ਸ਼ੁਰੂ ਕਰਨ ਵਿੱਚ ਥੋੜ੍ਹਾ ਸਮਾਂ ਲੱਗੇਗਾ ਜਦੋਂ ਤੱਕ ਇਹ ਭੇਜੇ ਜਾਣ ਲਈ ਤਿਆਰ ਨਾ ਹੋਵੇ, ਕਿਰਪਾ ਕਰਕੇ ਧੀਰਜ ਰੱਖੋ।"</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"ਅੰਤਰਕਿਰਿਆਤਮਕ ਰਿਪੋਰਟ"</string>
@@ -1767,12 +1765,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"ਅਗਲੀ ਵਾਰ ਜਦੋਂ ਤੁਸੀਂ ਪਹੁੰਚਯੋਗਤਾ ਬਟਨ ਨੂੰ ਟੈਪ ਕਰੋਗੇ, ਤਾਂ ਇਹ ਵਿਸ਼ੇਸ਼ਤਾ ਖੁੱਲ੍ਹ ਜਾਵੇਗੀ"</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"ਅਗਲੀ ਵਾਰ ਜਦੋਂ ਤੁਸੀਂ ਇਸ ਸ਼ਾਰਟਕੱਟ ਦੀ ਵਰਤੋਂ ਕਰੋਗੇ, ਤਾਂ ਇਹ ਵਿਸ਼ੇਸ਼ਤਾ ਖੁੱਲ੍ਹ ਜਾਵੇਗੀ। 2 ਉਂਗਲਾਂ ਨਾਲ ਆਪਣੀ ਸਕ੍ਰੀਨ ਦੇ ਹੇਠਾਂ ਤੋਂ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰ ਕੇ ਤੁਰੰਤ ਛੱਡੋ।"</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"ਅਗਲੀ ਵਾਰ ਜਦੋਂ ਤੁਸੀਂ ਇਸ ਸ਼ਾਰਟਕੱਟ ਦੀ ਵਰਤੋਂ ਕਰੋਗੇ, ਤਾਂ ਇਹ ਵਿਸ਼ੇਸ਼ਤਾ ਖੁੱਲ੍ਹ ਜਾਵੇਗੀ। 3 ਉਂਗਲਾਂ ਨਾਲ ਆਪਣੀ ਸਕ੍ਰੀਨ ਦੇ ਹੇਠਾਂ ਤੋਂ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰ ਕੇ ਤੁਰੰਤ ਛੱਡੋ।"</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"ਵੱਡਦਰਸ਼ੀਕਰਨ"</string>
<string name="user_switched" msgid="7249833311585228097">"ਮੌਜੂਦਾ ਉਪਭੋਗਤਾ <xliff:g id="NAME">%1$s</xliff:g>।"</string>
<string name="user_switching_message" msgid="1912993630661332336">"<xliff:g id="NAME">%1$s</xliff:g> \'ਤੇ ਸਵਿੱਚ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ…"</string>
@@ -2436,17 +2431,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"ਇਹ ਕਿਵੇਂ ਕੰਮ ਕਰਦਾ ਹੈ"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"ਵਿਚਾਰ-ਅਧੀਨ..."</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਅਣਲਾਕ ਦਾ ਦੁਬਾਰਾ ਸੈੱਟਅੱਪ ਕਰੋ"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> ਦੀ ਹੁਣ ਪਛਾਣ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ।"</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> ਅਤੇ <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> ਦੀ ਹੁਣ ਪਛਾਣ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ।"</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"<xliff:g id="FINGERPRINT">%s</xliff:g> ਦੀ ਹੁਣ ਪਛਾਣ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ। ਫਿੰਗਰਪ੍ਰਿੰਟ ਅਣਲਾਕ ਦਾ ਦੁਬਾਰਾ ਸੈੱਟਅੱਪ ਕਰੋ।"</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> ਅਤੇ <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> ਦੀ ਹੁਣ ਪਛਾਣ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ। ਫਿੰਗਰਪ੍ਰਿੰਟ ਅਣਲਾਕ ਦਾ ਦੁਬਾਰਾ ਸੈੱਟਅੱਪ ਕਰੋ।"</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"ਫ਼ੇਸ ਅਣਲਾਕ ਦਾ ਦੁਬਾਰਾ ਸੈੱਟਅੱਪ ਕਰੋ"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"ਤੁਹਾਡੇ ਚਿਹਰੇ ਦੇ ਮਾਡਲ ਦੀ ਹੁਣ ਪਛਾਣ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ। ਫ਼ੇਸ ਅਣਲਾਕ ਦਾ ਦੁਬਾਰਾ ਸੈੱਟਅੱਪ ਕਰੋ।"</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"ਸੈੱਟਅੱਪ ਕਰੋ"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"ਹੁਣੇ ਨਹੀਂ"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"<xliff:g id="USER_NAME">%s</xliff:g> ਲਈ ਅਲਾਰਮ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index a608fc765a93..81e5bf22f4ab 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -267,8 +267,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"Zgłoś błąd"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Zakończ sesję"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Zrzut ekranu"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"Zgłoś błąd"</string>
<string name="bugreport_message" msgid="5212529146119624326">"Informacje o bieżącym stanie urządzenia zostaną zebrane i wysłane e-mailem. Przygotowanie zgłoszenia błędu do wysłania chwilę potrwa, więc zachowaj cierpliwość."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"Raport interaktywny"</string>
@@ -2435,17 +2433,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Jak to działa"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Oczekiwanie…"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Skonfiguruj ponownie odblokowywanie odciskiem palca"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"Ten odcisk palca (<xliff:g id="FINGERPRINT">%s</xliff:g>) nie jest już rozpoznawany."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"Te odciski palców (<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> i <xliff:g id="FINGERPRINT_1">%2$s</xliff:g>) nie są już rozpoznawane."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"Ten odcisk palca (<xliff:g id="FINGERPRINT">%s</xliff:g>) nie jest już rozpoznawany. Skonfiguruj ponownie odblokowywanie odciskiem palca."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"Te odciski palców (<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> i <xliff:g id="FINGERPRINT_1">%2$s</xliff:g>) nie są już rozpoznawane. Skonfiguruj ponownie odblokowywanie odciskiem palca."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"Skonfiguruj ponownie rozpoznawanie twarzy"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"Model Twojej twarzy nie jest już rozpoznawany. Skonfiguruj ponownie rozpoznawanie twarzy."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Skonfiguruj"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Nie teraz"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"Alarm dla: <xliff:g id="USER_NAME">%s</xliff:g>"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index fa47d04fc702..c270c1cc2f3f 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -266,8 +266,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"Relatório de bug"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Finalizar sessão"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Captura de tela"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"Relatório de bug"</string>
<string name="bugreport_message" msgid="5212529146119624326">"Isto coletará informações sobre o estado atual do dispositivo para enviá-las em uma mensagem de e-mail. Após iniciar o relatório de bugs, será necessário aguardar algum tempo até que esteja pronto para ser enviado."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"Relatório interativo"</string>
@@ -2434,17 +2432,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Como funciona"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Pendente…"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Configurar o Desbloqueio por impressão digital de novo"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"A impressão digital <xliff:g id="FINGERPRINT">%s</xliff:g> não é mais reconhecida."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"As impressões digitais <xliff:g id="FINGERPRINT_0">%1$s</xliff:g> e <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> não são mais reconhecidas."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"A impressão digital <xliff:g id="FINGERPRINT">%s</xliff:g> não é mais reconhecida. Configure o \"Desbloqueio por impressão digital\" de novo."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"As impressões digitais <xliff:g id="FINGERPRINT_0">%1$s</xliff:g> e <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> não são mais reconhecidas. Configure o \"Desbloqueio por impressão digital\" de novo."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"Configure o Desbloqueio facial de novo"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"Seu modelo de rosto não é mais reconhecido. Configure o \"Desbloqueio facial\" de novo."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Configuração"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Agora não"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"Alarme para <xliff:g id="USER_NAME">%s</xliff:g>"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 8a5230348a3c..cf07ea8c5406 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -266,8 +266,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"Relatório de erros"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Terminar sessão"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Capt. ecrã"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"Relatório de erro"</string>
<string name="bugreport_message" msgid="5212529146119624326">"Será recolhida informação sobre o estado atual do seu dispositivo a enviar através de uma mensagem de email. Demorará algum tempo até que o relatório de erro esteja pronto para ser enviado. Aguarde um pouco."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"Relatório interativo"</string>
@@ -1442,7 +1440,7 @@
<string name="fast_scroll_numeric_alphabet" msgid="2529539945421557329">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="alert_windows_notification_channel_group_name" msgid="6063891141815714246">"Sobreposição a outras apps"</string>
<string name="alert_windows_notification_channel_name" msgid="3437528564303192620">"A app <xliff:g id="NAME">%s</xliff:g> sobrepõe-se a outras aplicações"</string>
- <string name="alert_windows_notification_title" msgid="6331662751095228536">"O <xliff:g id="NAME">%s</xliff:g> sobrepõe-se a outras app"</string>
+ <string name="alert_windows_notification_title" msgid="6331662751095228536">"<xliff:g id="NAME">%s</xliff:g> sobrepõe-se a outras app"</string>
<string name="alert_windows_notification_message" msgid="6538171456970725333">"Se não quer que a app <xliff:g id="NAME">%s</xliff:g> utilize esta funcionalidade, toque para abrir as definições e desative-a."</string>
<string name="alert_windows_notification_turn_off_action" msgid="7805857234839123780">"Desativar"</string>
<string name="ext_media_checking_notification_title" msgid="8299199995416510094">"A verificar o <xliff:g id="NAME">%s</xliff:g>…"</string>
@@ -2190,7 +2188,7 @@
<string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"O Bluetooth continuará ativado durante o modo de avião."</string>
<string name="car_loading_profile" msgid="8219978381196748070">"A carregar…"</string>
<string name="file_count" msgid="3220018595056126969">"{count,plural, =1{{file_name} + # ficheiro}many{{file_name} + # ficheiros}other{{file_name} + # ficheiros}}"</string>
- <string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"Não existem pessoas recomendadas com quem partilhar"</string>
+ <string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"Sem pessoas recomendadas com quem partilhar"</string>
<string name="chooser_all_apps_button_label" msgid="3230427756238666328">"Lista de aplicações"</string>
<string name="usb_device_resolve_prompt_warn" msgid="325871329788064199">"Esta app não recebeu autorização de gravação, mas pode capturar áudio através deste dispositivo USB."</string>
<string name="accessibility_system_action_home_label" msgid="3234748160850301870">"Página inicial"</string>
@@ -2434,17 +2432,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Como funciona"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Pendente…"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Configure o Desbloqueio por impressão digital novamente"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"Já não é possível reconhecer <xliff:g id="FINGERPRINT">%s</xliff:g>."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"Já não é possível reconhecer <xliff:g id="FINGERPRINT_0">%1$s</xliff:g> e <xliff:g id="FINGERPRINT_1">%2$s</xliff:g>."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"Já não é possível reconhecer <xliff:g id="FINGERPRINT">%s</xliff:g>. Configure o Desbloqueio por impressão digital novamente."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"Já não é possível reconhecer <xliff:g id="FINGERPRINT_0">%1$s</xliff:g> e <xliff:g id="FINGERPRINT_1">%2$s</xliff:g>. Configure o Desbloqueio por impressão digital novamente."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"Configure o Desbloqueio facial novamente"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"Já não é possível reconhecer o seu modelo de rosto. Configure o Desbloqueio facial novamente."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Configurar"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Agora não"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"Alarme de <xliff:g id="USER_NAME">%s</xliff:g>"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index fa47d04fc702..c270c1cc2f3f 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -266,8 +266,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"Relatório de bug"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Finalizar sessão"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Captura de tela"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"Relatório de bug"</string>
<string name="bugreport_message" msgid="5212529146119624326">"Isto coletará informações sobre o estado atual do dispositivo para enviá-las em uma mensagem de e-mail. Após iniciar o relatório de bugs, será necessário aguardar algum tempo até que esteja pronto para ser enviado."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"Relatório interativo"</string>
@@ -2434,17 +2432,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Como funciona"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Pendente…"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Configurar o Desbloqueio por impressão digital de novo"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"A impressão digital <xliff:g id="FINGERPRINT">%s</xliff:g> não é mais reconhecida."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"As impressões digitais <xliff:g id="FINGERPRINT_0">%1$s</xliff:g> e <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> não são mais reconhecidas."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"A impressão digital <xliff:g id="FINGERPRINT">%s</xliff:g> não é mais reconhecida. Configure o \"Desbloqueio por impressão digital\" de novo."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"As impressões digitais <xliff:g id="FINGERPRINT_0">%1$s</xliff:g> e <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> não são mais reconhecidas. Configure o \"Desbloqueio por impressão digital\" de novo."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"Configure o Desbloqueio facial de novo"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"Seu modelo de rosto não é mais reconhecido. Configure o \"Desbloqueio facial\" de novo."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Configuração"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Agora não"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"Alarme para <xliff:g id="USER_NAME">%s</xliff:g>"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 9c6f87e64cd6..e490ac5eb556 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -266,8 +266,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"Raport despre erori"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Încheie sesiunea"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Instantaneu"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"Raport de eroare"</string>
<string name="bugreport_message" msgid="5212529146119624326">"Acest raport va colecta informații despre starea actuală a dispozitivului, pentru a le trimite într-un e-mail. Ai răbdare după pornirea raportului despre erori până când va fi gata de trimis."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"Raport interactiv"</string>
@@ -1768,12 +1766,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"Funcția se va deschide data viitoare când atingi butonul de accesibilitate"</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"Funcția se va deschide data viitoare când folosești această comandă rapidă. Glisează în sus cu două degete din partea de jos a ecranului și ridică-le rapid."</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"Funcția se va deschide data viitoare când folosești această comandă rapidă. Glisează în sus cu trei degete din partea de jos a ecranului și ridică-le rapid."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Mărire"</string>
<string name="user_switched" msgid="7249833311585228097">"Utilizator curent: <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="1912993630661332336">"Se comută la <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2437,17 +2432,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Cum funcționează"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"În așteptare..."</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Configurează din nou Deblocarea cu amprenta"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> nu mai poate fi recunoscută."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> și <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> nu mai pot fi recunoscute."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"<xliff:g id="FINGERPRINT">%s</xliff:g> nu mai poate fi recunoscută. Configurează din nou Deblocarea cu amprenta."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> și <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> nu mai pot fi recunoscute. Configurează din nou Deblocarea cu amprenta."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"Reconfigurează Deblocarea facială"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"Modelul tău facial nu mai poate fi recunoscut. Configurează din nou Deblocarea facială."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Configurează"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Nu acum"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"Alarmă pentru <xliff:g id="USER_NAME">%s</xliff:g>"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index ac2e5638780f..923d2b49526c 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -267,8 +267,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"Отчет об ошибке"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Закончить сеанс"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Скриншот"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"Отчет об ошибке"</string>
<string name="bugreport_message" msgid="5212529146119624326">"Информация о текущем состоянии вашего устройства будет собрана и отправлена по электронной почте. Подготовка отчета займет некоторое время."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"Интерактивный отчет"</string>
@@ -1769,12 +1767,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"Функция теперь будет включаться при нажатии кнопки специальных возможностей."</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"Функция теперь будет включаться при выполнении действия быстрого запуска. Проведите двумя пальцами по экрану снизу вверх."</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"Функция теперь будет включаться при выполнении действия быстрого запуска. Проведите тремя пальцами по экрану снизу вверх."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Увеличение"</string>
<string name="user_switched" msgid="7249833311585228097">"Выбран аккаунт пользователя <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="1912993630661332336">"Смена профиля на \"<xliff:g id="NAME">%1$s</xliff:g>\"…"</string>
@@ -2438,17 +2433,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Узнать принцип работы"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Обработка…"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Настройте разблокировку по отпечатку пальца заново"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"Отпечаток \"<xliff:g id="FINGERPRINT">%s</xliff:g>\" больше нельзя распознать."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"Отпечатки \"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g>\" и \"<xliff:g id="FINGERPRINT_1">%2$s</xliff:g>\" больше нельзя распознать."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"Отпечаток \"<xliff:g id="FINGERPRINT">%s</xliff:g>\" больше нельзя распознать. Настройте разблокировку по отпечатку пальца снова."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"Отпечатки \"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g>\" и \"<xliff:g id="FINGERPRINT_1">%2$s</xliff:g>\" больше нельзя распознать. Настройте разблокировку по отпечатку пальца снова."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"Настройте фейсконтроль заново"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"Вашу модель лица больше нельзя распознать. Настройте фейсконтроль снова."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Настроить"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Не сейчас"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"Будильник пользователя <xliff:g id="USER_NAME">%s</xliff:g>"</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index fd8b536b03ce..992f8aa0f2eb 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -265,8 +265,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"දෝෂ වර්තාව"</string>
<string name="global_action_logout" msgid="6093581310002476511">"සැසිය අවසන් කරන්න"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"තිර රුව"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"දෝෂ වර්තාව"</string>
<string name="bugreport_message" msgid="5212529146119624326">"ඊ-තැපැල් පණිවිඩයක් ලෙස යැවීමට මෙය ඔබගේ වත්මන් උපාංග තත්වය ගැන තොරතුරු එකතු කරනු ඇත. දෝෂ වාර්තාව ආරම්භ කර එය යැවීමට සූදානම් කරන තෙක් එයට කිසියම් කාලයක් ගතවනු ඇත; කරුණාකර ඉවසන්න."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"අන්තර්ක්‍රියා වාර්."</string>
@@ -1767,12 +1765,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"මීළඟ වතාවේ ඔබ ප්‍රවේශ්‍යතා බොත්තම තට්ටු කිරීමෙන් විශේෂාංගය විවෘත වේ"</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"ඔබ මෙම කෙටිමඟ භාවිතා කරන මීළඟ වතාවේ විශේෂාංගය විවෘත වනු ඇත. ඔබේ තිරයෙහි පහළ සිට ඇඟිලි 2කින් ඉහළට ස්වයිප් කර ඉක්මනින් නිදහස් කරන්න."</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"ඔබ මෙම කෙටිමඟ භාවිතා කරන මීළඟ වතාවේ විශේෂාංගය විවෘත වනු ඇත. ඔබේ තිරයෙහි පහළ සිට ඇඟිලි 3කින් ඉහළට ස්වයිප් කර ඉක්මනින් නිදහස් කරන්න."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"විශාලනය"</string>
<string name="user_switched" msgid="7249833311585228097">"දැනට සිටින පරිශීලකයා <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="1912993630661332336">"<xliff:g id="NAME">%1$s</xliff:g> වෙත මාරු කරමින්…"</string>
@@ -2436,17 +2431,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"එය ක්‍රියා කරන ආකාරය"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"පොරොත්තුයි..."</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"ඇඟිලි සලකුණු අගුලු හැරීම නැවත සකසන්න"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> තවදුරටත් හඳුනා ගත නොහැක."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> සහ <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> තවදුරටත් හඳුනා ගත නොහැක."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"<xliff:g id="FINGERPRINT">%s</xliff:g> තවදුරටත් හඳුනා ගත නොහැක. ඇඟිලි සලකුණු අගුළු හැරීම නැවත පිහිටුවන්න."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> සහ <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> තවදුරටත් හඳුනා ගත නොහැක. ඇඟිලි සලකුණු අගුළු හැරීම නැවත පිහිටුවන්න."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"මුහුණෙන් අගුලු හැරීම නැවත සකසන්න"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"ඔබේ මුහුණු ආකෘතිය තවදුරටත් හඳුනා ගත නොහැක. මුහුණෙන් අගුළු හැරීම නැවත පිහිටුවන්න."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"සකසන්න"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"දැන් නොවේ"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"<xliff:g id="USER_NAME">%s</xliff:g> සඳහා එලාමය"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index c660fbd8ab2c..f3154c9d6c85 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -267,8 +267,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"Hlásenie o chybách"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Ukončiť reláciu"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Snímka obrazovky"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"Nahlásiť chybu"</string>
<string name="bugreport_message" msgid="5212529146119624326">"Týmto zhromaždíte informácie o aktuálnom stave zariadenia. Informácie je potom možné odoslať e-mailom, chvíľu však potrvá, kým bude hlásenie chyby pripravené na odoslanie. Prosíme vás preto o trpezlivosť."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"Interaktívne nahlásenie"</string>
@@ -1202,7 +1200,7 @@
<string name="low_internal_storage_view_text" msgid="8172166728369697835">"Niektoré systémové funkcie nemusia fungovať"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="7368968163411251788">"V úložisku nie je dostatok voľného miesta pre systém. Zaistite, aby ste mali 250 MB voľného miesta a zariadenie reštartujte."</string>
<string name="app_running_notification_title" msgid="8985999749231486569">"Aplikácia <xliff:g id="APP_NAME">%1$s</xliff:g> je spustená"</string>
- <string name="app_running_notification_text" msgid="5120815883400228566">"Klepnutím zobrazíte ďalšie informácie alebo zastavíte aplikáciu."</string>
+ <string name="app_running_notification_text" msgid="5120815883400228566">"Klepnutím zobrazíte ďalšie informácie alebo aplikáciu zastavíte."</string>
<string name="ok" msgid="2646370155170753815">"OK"</string>
<string name="cancel" msgid="6908697720451760115">"Zrušiť"</string>
<string name="yes" msgid="9069828999585032361">"OK"</string>
@@ -1443,7 +1441,7 @@
<string name="fast_scroll_numeric_alphabet" msgid="2529539945421557329">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="alert_windows_notification_channel_group_name" msgid="6063891141815714246">"Zobrazenie cez iné aplikácie"</string>
<string name="alert_windows_notification_channel_name" msgid="3437528564303192620">"<xliff:g id="NAME">%s</xliff:g> sa zobrazuje cez iné aplikácie"</string>
- <string name="alert_windows_notification_title" msgid="6331662751095228536">"<xliff:g id="NAME">%s</xliff:g> sa zobrazuje cez iné aplikácie"</string>
+ <string name="alert_windows_notification_title" msgid="6331662751095228536">"Aplikácia <xliff:g id="NAME">%s</xliff:g> sa zobrazuje nad inými aplikáciami"</string>
<string name="alert_windows_notification_message" msgid="6538171456970725333">"Ak nechcete, aby aplikácia <xliff:g id="NAME">%s</xliff:g> používala túto funkciu, klepnutím otvorte nastavenia a vypnite ju."</string>
<string name="alert_windows_notification_turn_off_action" msgid="7805857234839123780">"Vypnúť"</string>
<string name="ext_media_checking_notification_title" msgid="8299199995416510094">"Kontroluje sa <xliff:g id="NAME">%s</xliff:g>…"</string>
@@ -1769,12 +1767,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"Táto funkcia sa otvorí, keď nabudúce klepnete na tlačidlo dostupnosti"</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"Táto funkcia sa otvorí, keď nabudúce použijete túto skratku. Potiahnite zdola obrazovky dvoma prstami nahor a rýchlo uvoľnite."</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"Táto funkcia sa otvorí, keď nabudúce použijete túto skratku. Potiahnite zdola obrazovky troma prstami nahor a rýchlo uvoľnite."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Zväčšenie"</string>
<string name="user_switched" msgid="7249833311585228097">"Aktuálny používateľ je <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="1912993630661332336">"Prepína sa na účet <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2438,17 +2433,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Ako to funguje"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Nespracovaná…"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Znova nastavte odomknutie odtlačkom prsta"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> sa už nedari rozpoznať."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> a <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> sa už nedari rozpoznať."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"<xliff:g id="FINGERPRINT">%s</xliff:g> sa už nedari rozpoznať. Znova nastavte odomknutie odtlačkom prsta."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> a <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> sa už nedari rozpoznať. Znova nastavte odomknutie odtlačkom prsta."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"Znova nastavte odomknutie tvárou"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"Váš model tváre sa už nedari rozpoznať. Znova nastavte odomknutie tvárou."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Nastaviť"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Teraz nie"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"Budík pre používateľa <xliff:g id="USER_NAME">%s</xliff:g>"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index b5f9dc591ea0..8a29452648cc 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -267,8 +267,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"Poročilo o napakah"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Končaj sejo"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Posnetek"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"Poročilo o napakah"</string>
<string name="bugreport_message" msgid="5212529146119624326">"S tem bodo zbrani podatki o trenutnem stanju naprave, ki bodo poslani v e-poštnem sporočilu. Izvedba poročila o napakah in priprava trajata nekaj časa, zato bodite potrpežljivi."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"Interaktivno poročilo"</string>
@@ -1769,12 +1767,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"Funkcija se bo odprla, ko se boste naslednjič dotaknili gumba za dostopnost"</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"Funkcija se bo odprla, ko boste naslednjič uporabili to bližnjico. Z dvema prstoma povlecite navzgor z dna zaslona in hitro spustite."</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"Funkcija se bo odprla, ko boste naslednjič uporabili to bližnjico. S tremi prsti povlecite navzgor z dna zaslona in hitro spustite."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Povečava"</string>
<string name="user_switched" msgid="7249833311585228097">"Trenutni uporabnik <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="1912993630661332336">"Preklapljanje na uporabnika <xliff:g id="NAME">%1$s</xliff:g> …"</string>
@@ -2438,17 +2433,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Kako deluje"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"V teku …"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Vnovična nastavitev odklepanja s prstnim odtisom"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"Odtisa »<xliff:g id="FINGERPRINT">%s</xliff:g>« ni več mogoče prepoznati."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"Odtisov »<xliff:g id="FINGERPRINT_0">%1$s</xliff:g>« in »<xliff:g id="FINGERPRINT_1">%2$s</xliff:g>« ni več mogoče prepoznati."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"Odtisa »<xliff:g id="FINGERPRINT">%s</xliff:g>« ni več mogoče prepoznati. Znova nastavite odklepanje s prstnim odtisom."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"Odtisov »<xliff:g id="FINGERPRINT_0">%1$s</xliff:g>« in »<xliff:g id="FINGERPRINT_1">%2$s</xliff:g>« ni več mogoče prepoznati. Znova nastavite odklepanje s prstnim odtisom."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"Vnovična nastavitev odklepanja z obrazom"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"Vašega modela obraza ni več mogoče prepoznati. Znova nastavite odklepanje z obrazom."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Nastavi"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Ne zdaj"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"Alarm za uporabnika <xliff:g id="USER_NAME">%s</xliff:g>"</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 35dd218c1d51..cba1f0874636 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -265,8 +265,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"Raport i defektit në kod"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Jepi fund sesionit"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Pamja e ekranit"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"Raporti i defekteve në kod"</string>
<string name="bugreport_message" msgid="5212529146119624326">"Ky funksion mundëson mbledhjen e informacioneve mbi gjendjen aktuale të pajisjes për ta dërguar si mesazh mail-i. Do të duhet pak kohë nga nisja e raportit të defekteve në kod. Faleminderit për durimin."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"Raport interaktiv"</string>
@@ -1767,12 +1765,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"Veçoria do të hapet herën tjetër kur të trokasësh te butoni i qasshmërisë"</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"Veçoria do të hapet herën tjetër kur të përdorësh këtë shkurtore. Rrëshqit shpejt lart me 2 gishta nga fundi i ekranit dhe lëshoje me shpejtësi."</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"Veçoria do të hapet herën tjetër kur të përdorësh këtë shkurtore. Rrëshqit shpejt lart me 3 gishta nga fundi i ekranit dhe lëshoje me shpejtësi."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Zmadhimi"</string>
<string name="user_switched" msgid="7249833311585228097">"Emri i përdoruesit aktual: <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="user_switching_message" msgid="1912993630661332336">"Po kalon në \"<xliff:g id="NAME">%1$s</xliff:g>\"…"</string>
@@ -2436,17 +2431,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Si funksionon"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Në pritje..."</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Konfiguro përsëri \"Shkyçjen me gjurmën e gishtit\""</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> nuk mund të njihet më."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> dhe <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> nuk mund të njihen më."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"<xliff:g id="FINGERPRINT">%s</xliff:g> nuk mund të njihet më. Konfiguro përsëri \"Shkyçjen me gjurmën e gishtit\"."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> dhe <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> nuk mund të njihen më. Konfiguro përsëri \"Shkyçjen me gjurmën e gishtit\"."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"Konfiguro \"Shkyçjen me fytyrë\" përsëri"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"Modeli yt i fytyrës nuk mund të njihet më. Konfiguro \"Shkyçjen me fytyrë\" përsëri."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Konfiguro"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Jo tani"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"Alarmi për <xliff:g id="USER_NAME">%s</xliff:g>"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index a979047f6458..afb8e6b91abf 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -266,8 +266,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"Јави грешку"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Заврши сесију"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Снимак екрана"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"Јави грешку"</string>
<string name="bugreport_message" msgid="5212529146119624326">"Овим ће се прикупити информације о тренутном стању уређаја како би биле послате у поруци е-поште. Од започињања извештаја о грешци до тренутка за његово слање проћи ће неко време; будите стрпљиви."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"Интерактив. извештај"</string>
@@ -1768,12 +1766,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"Функција ће се отворити када следећи пут додирнете дугме Приступачност"</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"Функција ће се отворити када следећи пут будете користили ову пречицу. Превуците нагоре од дна екрана са 2 прста и брзо пустите."</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"Функција ће се отворити када следећи пут будете користили ову пречицу. Превуците нагоре од дна екрана са 3 прста и брзо пустите."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Увећање"</string>
<string name="user_switched" msgid="7249833311585228097">"Актуелни корисник <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="1912993630661332336">"Пребацивање на <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2437,17 +2432,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Принцип рада"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"На чекању..."</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Поново подесите откључавање отиском прста"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> више не може да се препозна."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> и <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> више не могу да се препознају."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"<xliff:g id="FINGERPRINT">%s</xliff:g> више не може да се препозна. Поново подесите откључавање отиском прста."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> и <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> више не могу да се препознају. Поново подесите откључавање отиском прста."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"Поново подесите откључавање лицем"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"Ваш модел лица више не може да се препозна. Поново подесите откључавање лицем."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Подеси"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Не сада"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"Аларм за: <xliff:g id="USER_NAME">%s</xliff:g>"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index eac67f57baab..6dee8ea36026 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -265,8 +265,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"Felrapport"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Avsluta session"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Skärmbild"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"Felrapport"</string>
<string name="bugreport_message" msgid="5212529146119624326">"Nu hämtas information om aktuell status för enheten, som sedan skickas i ett e-postmeddelade. Det tar en liten stund innan felrapporten är färdig och kan skickas, så vi ber dig ha tålamod."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"Interaktiv rapport"</string>
@@ -1767,12 +1765,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"Funktionen öppnas nästa gång du trycker på tillgänglighetsknappen"</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"Funktionen öppnas nästa gång du använder kortkommandot. Svep uppåt med två fingrar från skärmens nederkant och släpp snabbt."</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"Funktionen öppnas nästa gång du använder kortkommandot. Svep uppåt med tre fingrar från skärmens nederkant och släpp snabbt."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Förstoring"</string>
<string name="user_switched" msgid="7249833311585228097">"Nuvarande användare: <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="1912993630661332336">"Byter till <xliff:g id="NAME">%1$s</xliff:g> …"</string>
@@ -2436,17 +2431,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Så fungerar det"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Väntar …"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Konfigurera fingeravtryckslås igen"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"Det går inte längre att känna igen <xliff:g id="FINGERPRINT">%s</xliff:g>."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"Det går inte längre att känna igen <xliff:g id="FINGERPRINT_0">%1$s</xliff:g> och <xliff:g id="FINGERPRINT_1">%2$s</xliff:g>."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"Det går inte längre att känna igen <xliff:g id="FINGERPRINT">%s</xliff:g>. Konfigurera fingeravtryckslås igen."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"Det går inte längre att känna igen <xliff:g id="FINGERPRINT_0">%1$s</xliff:g> och <xliff:g id="FINGERPRINT_1">%2$s</xliff:g>. Konfigurera fingeravtryckslås igen."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"Konfigurera ansiktslås igen"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"Det går inte längre att känna igen din ansiktsmodell. Konfigurera ansiktslåset på nytt."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Ställ in"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Inte nu"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"Alarm för <xliff:g id="USER_NAME">%s</xliff:g>"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 409603c7967d..05cc4bba1871 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -265,8 +265,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"Ripoti ya hitilafu"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Maliza kipindi"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Picha ya skrini"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"Ripoti ya hitilafu"</string>
<string name="bugreport_message" msgid="5212529146119624326">"Hii itakusanya maelezo kuhusu hali ya kifaa chako kwa sasa, na itume kama barua pepe. Itachukua muda mfupi tangu ripoti ya hitilafu ianze kuzalishwa hadi iwe tayari kutumwa; vumilia."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"Ripoti ya kushirikiana"</string>
@@ -1767,12 +1765,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"Kipengele kitafunguka utakapogusa tena kitufe cha zana za ufikivu"</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"Kipengele kitafunguka utakapotumia tena njia hii ya mkato. Telezesha vidole 2 kuanzia sehemu ya chini ya skrini yako kwenda juu kisha uachilie haraka."</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"Kipengele kitafunguka utakapotumia tena njia hii ya mkato. Telezesha vidole 3 kuanzia sehemu ya chini ya skrini yako kwenda juu kisha uachilie haraka."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Ukuzaji"</string>
<string name="user_switched" msgid="7249833311585228097">"Mtumiaji wa sasa <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="1912993630661332336">"Inaenda kwa <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2436,17 +2431,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Utaratibu wake"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Inashughulikiwa..."</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Weka tena mipangilio ya Kufungua kwa Alama ya Kidole"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> haitambuliki tena."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> na <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> havitambuliki tena."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"<xliff:g id="FINGERPRINT">%s</xliff:g> haitambuliki tena. Weka tena mipangilio ya Kufungua kwa Alama ya Kidole."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> na <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> havitambuliki tena. Weka tena mipangilio ya Kufungua kwa Alama ya Kidole."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"Weka tena mipangilio ya Kufungua kwa Uso"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"Muundo wa uso wako hautambuliki tena. Weka tena mipangilio ya Kufungua kwa Uso."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Weka mipangilio"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Si sasa"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"King\'ora cha <xliff:g id="USER_NAME">%s</xliff:g>"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index f76b2fceda1b..78513d6b580b 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -265,8 +265,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"பிழை அறிக்கை"</string>
<string name="global_action_logout" msgid="6093581310002476511">"அமர்வை முடிக்கிறது"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"ஸ்கிரீன்ஷாட்"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"பிழை அறிக்கை"</string>
<string name="bugreport_message" msgid="5212529146119624326">"உங்கள் நடப்புச் சாதன நிலையை மின்னஞ்சல் செய்தியாக அனுப்ப, அது குறித்த தகவலை இது சேகரிக்கும். பிழை அறிக்கையைத் தொடங்குவதில் இருந்து, அது அனுப்புவதற்குத் தயாராகும் வரை, இதற்குச் சிறிது நேரம் ஆகும்; பொறுமையாகக் காத்திருக்கவும்."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"ஊடாடத்தக்க அறிக்கை"</string>
@@ -1767,12 +1765,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"அடுத்த முறை மாற்றுத்திறன் பட்டனை நீங்கள் தட்டும்போது அம்சம் திறக்கும்"</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"அடுத்த முறை இந்த ஷார்ட்கட்டை நீங்கள் பயன்படுத்தும்போது அம்சம் திறக்கும். 2 விரல்களால் திரையின் கீழிருந்து மேல்நோக்கி ஸ்வைப் செய்து விரைவாக விரல்களை எடுக்கவும்."</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"அடுத்த முறை இந்த ஷார்ட்கட்டை நீங்கள் பயன்படுத்தும்போது அம்சம் திறக்கும். 3 விரல்களால் திரையின் கீழிருந்து மேல்நோக்கி ஸ்வைப் செய்து விரைவாக விரல்களை எடுக்கவும்."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"பெரிதாக்கல்"</string>
<string name="user_switched" msgid="7249833311585228097">"நடப்பு பயனர் <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="1912993630661332336">"<xliff:g id="NAME">%1$s</xliff:g>க்கு மாறுகிறது…"</string>
@@ -2436,17 +2431,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"இது செயல்படும் விதம்"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"நிலுவையிலுள்ளது..."</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"கைரேகை அன்லாக் அம்சத்தை மீண்டும் அமையுங்கள்"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g>ஐ இனி அடையாளம் காண முடியாது."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g>, <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> ஆகியவற்றை இனி அடையாளம் காண முடியாது."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"<xliff:g id="FINGERPRINT">%s</xliff:g>ஐ இனி அடையாளம் காண முடியாது. கைரேகை அன்லாக் அம்சத்தை மீண்டும் அமையுங்கள்."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g>, <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> ஆகியவற்றை இனி அடையாளம் காண முடியாது. கைரேகை அன்லாக் அம்சத்தை மீண்டும் அமையுங்கள்."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"\'முகம் காட்டித் திறத்தல்\' அம்சத்தை மீண்டும் அமையுங்கள்"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"உங்கள் முகத் தோற்றப் பதிவை இனி அடையாளம் காண முடியாது. முகம் காட்டித் திறத்தல் அம்சத்தை மீண்டும் அமையுங்கள்."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"அமை"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"இப்போது வேண்டாம்"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"<xliff:g id="USER_NAME">%s</xliff:g>க்கான அலாரம்"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 63c6cfe51a6f..5f55515a2bda 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -265,8 +265,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"బగ్ రిపోర్ట్‌"</string>
<string name="global_action_logout" msgid="6093581310002476511">"సెషన్‌ను ముగించు"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"స్క్రీన్‌షాట్"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"బగ్ రిపోర్ట్‌"</string>
<string name="bugreport_message" msgid="5212529146119624326">"ఇది ఈమెయిల్‌ మెసేజ్‌ రూపంలో పంపడానికి మీ ప్రస్తుత పరికర స్థితి గురించి సమాచారాన్ని సేకరిస్తుంది. బగ్ రిపోర్ట్‌ను ప్రారంభించడం మొదలుకొని పంపడానికి సిద్ధం చేసే వరకు ఇందుకు కొంత సమయం పడుతుంది; దయచేసి ఓపిక పట్టండి."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"ప్రభావశీల రిపోర్ట్‌"</string>
@@ -2433,17 +2431,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"ఇది ఎలా పని చేస్తుంది"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"పెండింగ్‌లో ఉంది..."</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"వేలిముద్ర అన్‌లాక్‌ను మళ్లీ సెటప్ చేయండి"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g>‌ను ఇకపై గుర్తించడం సాధ్యం కాదు."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g>, <xliff:g id="FINGERPRINT_1">%2$s</xliff:g>‌లను ఇకపై గుర్తించడం సాధ్యం కాదు."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"<xliff:g id="FINGERPRINT">%s</xliff:g>‌ను ఇకపై గుర్తించడం సాధ్యం కాదు. వేలిముద్ర అన్‌లాక్‌ను మళ్లీ సెటప్ చేయండి."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g>, <xliff:g id="FINGERPRINT_1">%2$s</xliff:g>‌లను ఇకపై గుర్తించడం సాధ్యం కాదు. వేలిముద్ర అన్‌లాక్‌ను మళ్లీ సెటప్ చేయండి."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"ఫేస్ అన్‌లాక్‌ను మళ్లీ సెటప్ చేయండి"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"మీ ఫేస్ మోడల్‌ను ఇకపై గుర్తించడం సాధ్యం కాదు. ఫేస్ అన్‌లాక్‌ను మళ్లీ సెటప్ చేయండి."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"సెటప్ చేయండి"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"ఇప్పుడు కాదు"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"<xliff:g id="USER_NAME">%s</xliff:g> కోసం అలారం"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 9d244eeeacfb..358b38af5453 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -265,8 +265,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"รายงานข้อบกพร่อง"</string>
<string name="global_action_logout" msgid="6093581310002476511">"จบเซสชัน"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"ภาพหน้าจอ"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"รายงานข้อบกพร่อง"</string>
<string name="bugreport_message" msgid="5212529146119624326">"การดำเนินการนี้จะรวบรวมข้อมูลเกี่ยวกับสถานะปัจจุบันของอุปกรณ์ของคุณ โดยจะส่งไปในรูปแบบข้อความอีเมล อาจใช้เวลาสักครู่ตั้งแต่เริ่มการสร้างรายงานข้อบกพร่องจนกระทั่งเสร็จสมบูรณ์ โปรดอดทนรอ"</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"รายงานแบบอินเทอร์แอกทีฟ"</string>
@@ -1767,12 +1765,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"ฟีเจอร์นี้จะเปิดขึ้นในครั้งถัดไปที่คุณแตะปุ่มการช่วยเหลือพิเศษ"</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"ฟีเจอร์นี้จะเปิดขึ้นในครั้งถัดไปที่คุณใช้ทางลัดนี้ ใช้ 2 นิ้วปัดขึ้นจากด้านล่างของหน้าจอและปล่อยอย่างรวดเร็ว"</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"ฟีเจอร์นี้จะเปิดขึ้นในครั้งถัดไปที่คุณใช้ทางลัดนี้ ใช้ 3 นิ้วปัดขึ้นจากด้านล่างของหน้าจอและปล่อยอย่างรวดเร็ว"</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"การขยาย"</string>
<string name="user_switched" msgid="7249833311585228097">"ผู้ใช้ปัจจุบัน <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="user_switching_message" msgid="1912993630661332336">"กำลังเปลี่ยนเป็น<xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2436,17 +2431,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"วิธีการทำงาน"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"รอดำเนินการ..."</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"ตั้งค่าการปลดล็อกด้วยลายนิ้วมืออีกครั้ง"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"ระบบไม่จดจำ <xliff:g id="FINGERPRINT">%s</xliff:g> อีกต่อไป"</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"ระบบไม่จดจำ <xliff:g id="FINGERPRINT_0">%1$s</xliff:g> และ <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> อีกต่อไป"</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"ระบบไม่จดจำ <xliff:g id="FINGERPRINT">%s</xliff:g> อีกต่อไป ตั้งค่าการปลดล็อกด้วยลายนิ้วมืออีกครั้ง"</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"ระบบไม่จดจำ <xliff:g id="FINGERPRINT_0">%1$s</xliff:g> และ <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> อีกต่อไป ตั้งค่าการปลดล็อกด้วยลายนิ้วมืออีกครั้ง"</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"ตั้งค่าการปลดล็อกด้วยใบหน้าอีกครั้ง"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"ระบบไม่จดจำรูปแบบใบหน้าของคุณอีกต่อไป ตั้งค่าการปลดล็อกด้วยใบหน้าอีกครั้ง"</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"ตั้งค่า"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"ไว้ทีหลัง"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"นาฬิกาปลุกสำหรับ <xliff:g id="USER_NAME">%s</xliff:g>"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index bcb70bfec18b..2d8880182863 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -265,8 +265,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"Ulat sa bug"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Tapusin ang session"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Screenshot"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"Ulat ng bug"</string>
<string name="bugreport_message" msgid="5212529146119624326">"Mangongolekta ito ng impormasyon tungkol sa kasalukuyang katayuan ng iyong device, na ipapadala bilang mensaheng e-mail. Gugugol ito ng kaunting oras mula sa pagsisimula ng ulat sa bug hanggang sa handa na itong maipadala; mangyaring magpasensya."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"Interactive na ulat"</string>
@@ -1767,12 +1765,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"Magbubukas ang feature sa susunod na i-tap mo ang button ng accessibility"</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"Magbubukas ang feature sa susunod na gamitin mo ang shortcut na ito. Mag-swipe pataas gamit ang 2 daliri mula sa ibaba ng iyong screen at mabilis na i-release."</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"Magbubukas ang feature sa susunod na gamitin mo ang shortcut na ito. Mag-swipe pataas gamit ang 3 daliri mula sa ibaba ng iyong screen at mabilis na i-release."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Pag-magnify"</string>
<string name="user_switched" msgid="7249833311585228097">"Kasalukuyang user <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="1912993630661332336">"Lumilipat kay <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2436,17 +2431,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Paano ito gumagana"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Nakabinbin..."</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"I-set up ulit ang Pag-unlock Gamit ang Fingerprint"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"Hindi na makilala ang <xliff:g id="FINGERPRINT">%s</xliff:g>."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"Hindi na makilala ang <xliff:g id="FINGERPRINT_0">%1$s</xliff:g> at <xliff:g id="FINGERPRINT_1">%2$s</xliff:g>."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"Hindi na makilala ang <xliff:g id="FINGERPRINT">%s</xliff:g>. I-set up ulit ang Pag-unlock Gamit ang Fingerprint."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"Hindi na makilala ang <xliff:g id="FINGERPRINT_0">%1$s</xliff:g> at <xliff:g id="FINGERPRINT_1">%2$s</xliff:g>. I-set up ulit ang Pag-unlock Gamit ang Fingerprint."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"I-set up ulit ang Pag-unlock Gamit ang Mukha"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"Hindi na makilala ang iyong face model. I-set up ulit ang Pag-unlock Gamit ang Mukha."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"I-set up"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Huwag muna"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"Alarm para kay <xliff:g id="USER_NAME">%s</xliff:g>"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 03863c571013..d3e61dcee461 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -265,8 +265,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"Hata raporu"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Oturumu sonlandır"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Ekran görüntüsü"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"Hata raporu"</string>
<string name="bugreport_message" msgid="5212529146119624326">"Bu rapor, e-posta iletisi olarak göndermek üzere cihazınızın şu anki durumuyla ilgili bilgi toplar. Hata raporu başlatıldıktan sonra hazır olması biraz zaman alabilir, lütfen sabırlı olun."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"Etkileşimli rapor"</string>
@@ -1767,12 +1765,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"Özellik, erişilebilirlik düğmesine bir sonraki dokunuşunuzda açılır."</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"Özellik, bu kısayolu bir sonraki kullanışınızda açılır. Ekranın alt kısmından 2 parmağınızla yukarı doğru kaydırın ve hızlıca bırakın."</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"Özellik, bu kısayolu bir sonraki kullanışınızda açılır. Ekranın alt kısmından 3 parmağınızla yukarı doğru kaydırın ve hızlıca bırakın."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Büyütme"</string>
<string name="user_switched" msgid="7249833311585228097">"Geçerli kullanıcı: <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="1912993630661332336">"<xliff:g id="NAME">%1$s</xliff:g> adlı kullanıcıya geçiliyor…"</string>
@@ -2436,17 +2431,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"İşleyiş şekli"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Bekliyor..."</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Parmak İzi Kilidi\'ni tekrar kurun"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> artık tanınamayacak."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> ve <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> artık tanınamayacak."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"<xliff:g id="FINGERPRINT">%s</xliff:g> artık tanınamayacak. Parmak İzi Kilidi\'ni tekrar kurun."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> ve <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> artık tanınamayacak. Parmak İzi Kilidi\'ni tekrar kurun."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"Yüz Tanıma Kilidi\'ni tekrar kurun"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"Yüz modeliniz artık tanınamayacak. Yüz Tanıma Kilidi\'ni tekrar kurun."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Ayarla"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Şimdi değil"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"<xliff:g id="USER_NAME">%s</xliff:g> için alarm"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 7ffd66aeeb02..81434c207e89 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -267,8 +267,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"Звіт про помилки"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Завершити сеанс"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Знімок екрана"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"Звіт про помилку"</string>
<string name="bugreport_message" msgid="5212529146119624326">"Інформація про поточний стан вашого пристрою буде зібрана й надіслана електронною поштою. Підготовка звіту триватиме певний час."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"Інтерактивний звіт"</string>
@@ -1769,12 +1767,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"Функція відкриється, коли ви наступного разу натиснете кнопку функцій доступності"</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"Функція відкриється, коли ви наступного разу скористаєтеся цією швидкою командою. Проведіть двома пальцями вгору від низу екрана й швидко відпустіть."</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"Функція відкриється, коли ви наступного разу скористаєтеся цією швидкою командою. Проведіть трьома пальцями вгору від низу екрана й швидко відпустіть."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Збільшення"</string>
<string name="user_switched" msgid="7249833311585228097">"Поточний користувач: <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="1912993630661332336">"Перехід у режим \"<xliff:g id="NAME">%1$s</xliff:g>\"…"</string>
@@ -2438,17 +2433,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Як це працює"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Обробка…"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Налаштуйте розблокування відбитком пальця повторно"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"Відбиток пальця <xliff:g id="FINGERPRINT">%s</xliff:g> більше не розпізнається."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"Відбитки пальців <xliff:g id="FINGERPRINT_0">%1$s</xliff:g> і <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> більше не розпізнаються."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"Відбиток пальця <xliff:g id="FINGERPRINT">%s</xliff:g> більше не розпізнається. Налаштуйте розблокування відбитком пальця повторно."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"Відбитки пальців <xliff:g id="FINGERPRINT_0">%1$s</xliff:g> і <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> більше не розпізнаються. Налаштуйте розблокування відбитком пальця повторно."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"Налаштуйте фейс-контроль повторно"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"Модель вашого обличчя більше не розпізнається. Налаштуйте фейс-контроль повторно."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Налаштувати"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Не зараз"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"Будильник користувача <xliff:g id="USER_NAME">%s</xliff:g>"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 1b14e674ed5f..8363933c94af 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -265,8 +265,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"بگ کی اطلاع"</string>
<string name="global_action_logout" msgid="6093581310002476511">"سیشن ختم کریں"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"اسکرین شاٹ"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"بگ رپورٹ"</string>
<string name="bugreport_message" msgid="5212529146119624326">"ایک ای میل پیغام کے بطور بھیجنے کیلئے، یہ آپ کے موجودہ آلہ کی حالت کے بارے میں معلومات جمع کرے گا۔ بگ کی اطلاع شروع کرنے سے لے کر بھیجنے کیلئے تیار ہونے تک اس میں تھوڑا وقت لگے گا؛ براہ کرم تحمل سے کام لیں۔"</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"متعامل رپورٹ"</string>
@@ -1767,12 +1765,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"اگلی بار جب آپ ایکسیسبیلٹی بٹن پر تھپتھپائیں گے تو خصوصیت کھل جائے گی"</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"اگلی بار جب آپ یہ شارٹ کٹ استعمال کریں گے تو خصوصیت کھل جائے گی۔ اپنی اسکرین کے نیچے سے 2 انگلیوں سے اوپر کی طرف سوائپ کریں اور تیزی سے ریلیز کریں۔"</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"اگلی بار جب آپ یہ شارٹ کٹ استعمال کریں گے تو خصوصیت کھل جائے گی۔ اپنی اسکرین کے نیچے سے 3 انگلیوں سے اوپر کی طرف سوائپ کریں اور تیزی سے ریلیز کریں۔"</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"میگنیفکیشن"</string>
<string name="user_switched" msgid="7249833311585228097">"موجودہ صارف <xliff:g id="NAME">%1$s</xliff:g>۔"</string>
<string name="user_switching_message" msgid="1912993630661332336">"<xliff:g id="NAME">%1$s</xliff:g> پر سوئچ کیا جا رہا ہے…"</string>
@@ -2436,17 +2431,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"اس کے کام کرنے کا طریقہ"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"زیر التواء..."</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"فنگر پرنٹ اَن لاک کو دوبارہ سیٹ اپ کریں"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> مزید پہچانا نہیں جا سکتا۔"</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> اور <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> کو مزید پہچانا نہیں جا سکتا۔"</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"<xliff:g id="FINGERPRINT">%s</xliff:g> مزید پہچانا نہیں جا سکتا۔ فنگر پرنٹ اَن لاک کو دوبارہ سیٹ اپ کریں۔"</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> اور <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> کو مزید پہچانا نہیں جا سکتا۔ فنگر پرنٹ اَن لاک کو دوبارہ سیٹ اپ کریں۔"</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"فیس اَن لاک کو دوبارہ سیٹ اپ کریں"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"آپ کے چہرے کا ماڈل مزید پہچانا نہیں جا سکتا۔ فیس اَن لاک کو دوبارہ سیٹ اپ کریں۔"</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"سیٹ اپ کریں"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"ابھی نہیں"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"<xliff:g id="USER_NAME">%s</xliff:g> کیلئے الارم"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index 1c8879ef8353..21abadad42cd 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -265,8 +265,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"Xatoliklar hisoboti"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Seansni yakunlash"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Skrinshot"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"Xatoliklar hisoboti"</string>
<string name="bugreport_message" msgid="5212529146119624326">"Qurilmangiz holati haqidagi ma’lumotlar to‘planib, e-pochta orqali yuboriladi. Hisobotni tayyorlash biroz vaqt olishi mumkin."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"Interaktiv hisobot"</string>
@@ -2433,17 +2431,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Ishlash tartibi"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Kutilmoqda..."</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Barmoq izi bilan ochish funksiyasini qayta sozlang"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> endi tanilmaydi."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> va <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> endi tanilmaydi."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"<xliff:g id="FINGERPRINT">%s</xliff:g> endi tanilmaydi. Barmoq izi bilan ochishni qayta sozlang."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> va <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> endi tanilmaydi. Barmoq izi bilan ochishni qayta sozlang."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"Yuz bilan ochishni qayta sozlash"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"Yuzingiz modeli endi tanilmaydi. Yuz bilan ochishni qayta sozlang."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Sozlash"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Hozir emas"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"<xliff:g id="USER_NAME">%s</xliff:g> uchun signal"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 5d8597eeaca6..0141d9d86a0d 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -265,8 +265,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"Báo cáo lỗi"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Kết thúc phiên"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Chụp màn hình"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"Báo cáo lỗi"</string>
<string name="bugreport_message" msgid="5212529146119624326">"Báo cáo này sẽ thu thập thông tin về tình trạng thiết bị hiện tại của bạn, để gửi dưới dạng thông báo qua email. Sẽ mất một chút thời gian kể từ khi bắt đầu báo cáo lỗi cho tới khi báo cáo sẵn sàng để gửi; xin vui lòng kiên nhẫn."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"Báo cáo tương tác"</string>
@@ -1441,7 +1439,7 @@
<string name="fast_scroll_numeric_alphabet" msgid="2529539945421557329">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="alert_windows_notification_channel_group_name" msgid="6063891141815714246">"Hiển thị trên các ứng dụng khác"</string>
<string name="alert_windows_notification_channel_name" msgid="3437528564303192620">"<xliff:g id="NAME">%s</xliff:g> hiển thị trên các ứng dụng khác"</string>
- <string name="alert_windows_notification_title" msgid="6331662751095228536">"<xliff:g id="NAME">%s</xliff:g> hiển thị trên ứng dụng khác"</string>
+ <string name="alert_windows_notification_title" msgid="6331662751095228536">"<xliff:g id="NAME">%s</xliff:g> đang hiện trên các ứng dụng khác"</string>
<string name="alert_windows_notification_message" msgid="6538171456970725333">"Nếu bạn không muốn <xliff:g id="NAME">%s</xliff:g> sử dụng tính năng này, hãy nhấn để mở cài đặt và tắt tính năng này."</string>
<string name="alert_windows_notification_turn_off_action" msgid="7805857234839123780">"Tắt"</string>
<string name="ext_media_checking_notification_title" msgid="8299199995416510094">"Đang kiểm tra <xliff:g id="NAME">%s</xliff:g>…"</string>
@@ -1767,12 +1765,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"Tính năng này sẽ được mở vào lần tới bạn nhấn nút hỗ trợ tiếp cận"</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"Tính năng này sẽ được mở vào lần tới bạn dùng lối tắt này. Hãy dùng 2 ngón tay vuốt từ cuối màn hình lên rồi thả tay nhanh."</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"Tính năng này sẽ được mở vào lần tới bạn dùng lối tắt này. Hãy dùng 3 ngón tay vuốt từ cuối màn hình lên rồi thả tay nhanh."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Phóng to"</string>
<string name="user_switched" msgid="7249833311585228097">"Người dùng hiện tại <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="1912993630661332336">"Đang chuyển sang <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2436,17 +2431,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Cách hoạt động"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Đang chờ xử lý..."</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Thiết lập lại tính năng Mở khoá bằng vân tay"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"Không nhận dạng được <xliff:g id="FINGERPRINT">%s</xliff:g> nữa."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"Không nhận dạng được <xliff:g id="FINGERPRINT_0">%1$s</xliff:g> và <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> nữa."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"Không nhận dạng được <xliff:g id="FINGERPRINT">%s</xliff:g> nữa. Hãy thiết lập lại tính năng Mở khoá bằng vân tay."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"Không nhận dạng được <xliff:g id="FINGERPRINT_0">%1$s</xliff:g> và <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> nữa. Hãy thiết lập lại tính năng Mở khoá bằng vân tay."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"Thiết lập lại tính năng Mở khoá bằng khuôn mặt"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"Không nhận dạng được mẫu khuôn mặt của bạn nữa. Hãy thiết lập lại tính năng Mở khoá bằng khuôn mặt."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Thiết lập"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Để sau"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"Chuông báo cho <xliff:g id="USER_NAME">%s</xliff:g>"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index a9a310512500..3a7c9067bb02 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -265,8 +265,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"错误报告"</string>
<string name="global_action_logout" msgid="6093581310002476511">"结束会话"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"屏幕截图"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"错误报告"</string>
<string name="bugreport_message" msgid="5212529146119624326">"这会收集有关当前设备状态的信息,并以电子邮件的形式进行发送。从开始生成错误报告到准备好发送需要一点时间,请耐心等待。"</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"互动式报告"</string>
@@ -1767,12 +1765,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"下次点按“无障碍”按钮时,将打开此功能"</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"下次使用此快捷手势时,将打开此功能。用 2 根手指从画面底部向上滑动,然后快速松开。"</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"下次使用此快捷手势时,将打开此功能。用 3 根手指从画面底部向上滑动,然后快速松开。"</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"放大功能"</string>
<string name="user_switched" msgid="7249833311585228097">"当前用户是<xliff:g id="NAME">%1$s</xliff:g>。"</string>
<string name="user_switching_message" msgid="1912993630661332336">"正在切换为<xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2436,17 +2431,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"运作方式"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"待归档…"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"重新设置指纹解锁功能"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"系统无法再识别<xliff:g id="FINGERPRINT">%s</xliff:g>。"</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"系统无法再识别<xliff:g id="FINGERPRINT_0">%1$s</xliff:g>和<xliff:g id="FINGERPRINT_1">%2$s</xliff:g>。"</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"系统无法再识别<xliff:g id="FINGERPRINT">%s</xliff:g>。请重新设置指纹解锁功能。"</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"系统无法再识别<xliff:g id="FINGERPRINT_0">%1$s</xliff:g>和<xliff:g id="FINGERPRINT_1">%2$s</xliff:g>。请重新设置指纹解锁功能。"</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"重新设置“人脸解锁”功能"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"系统无法再识别您的脸部模型。请重新设置人脸解锁功能。"</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"设置"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"以后再说"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"<xliff:g id="USER_NAME">%s</xliff:g>的闹钟"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 72e83088d8a5..a28efbed1b7f 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -265,8 +265,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"錯誤報告"</string>
<string name="global_action_logout" msgid="6093581310002476511">"結束工作階段"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"螢幕截圖"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"錯誤報告"</string>
<string name="bugreport_message" msgid="5212529146119624326">"這會收集你目前裝置狀態的相關資訊,並以電郵傳送給你。從開始建立錯誤報告到準備傳送需要一段時間,請耐心等候。"</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"互動報告"</string>
@@ -2433,17 +2431,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"運作方式"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"待處理…"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"重新設定「指紋解鎖」功能"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"無法再辨識<xliff:g id="FINGERPRINT">%s</xliff:g>。"</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"無法再辨識<xliff:g id="FINGERPRINT_0">%1$s</xliff:g>和<xliff:g id="FINGERPRINT_1">%2$s</xliff:g>。"</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"無法再辨識<xliff:g id="FINGERPRINT">%s</xliff:g>。請重新設定「指紋解鎖」功能。"</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"無法再辨識<xliff:g id="FINGERPRINT_0">%1$s</xliff:g>和<xliff:g id="FINGERPRINT_1">%2$s</xliff:g>。請重新設定「指紋解鎖」功能。"</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"重新設定「面孔解鎖」功能"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"無法再辨識你的面部模型。請重新設定「面孔解鎖」功能。"</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"設定"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"暫時不要"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"<xliff:g id="USER_NAME">%s</xliff:g>的鬧鐘"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index d971b0f25b65..ed49988885ed 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -265,8 +265,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"錯誤報告"</string>
<string name="global_action_logout" msgid="6093581310002476511">"結束"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"螢幕截圖"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"錯誤報告"</string>
<string name="bugreport_message" msgid="5212529146119624326">"這會收集你目前裝置狀態的相關資訊,以便透過電子郵件傳送。從錯誤報告開始建立到準備傳送的這段過程可能需要一點時間,敬請耐心等候。"</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"互動式報告"</string>
@@ -1199,7 +1197,7 @@
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"儲存空間即將用盡"</string>
<string name="low_internal_storage_view_text" msgid="8172166728369697835">"部分系統功能可能無法運作"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="7368968163411251788">"系統儲存空間不足。請確定你已釋出 250MB 的可用空間,然後重新啟動。"</string>
- <string name="app_running_notification_title" msgid="8985999749231486569">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」目前正在執行"</string>
+ <string name="app_running_notification_title" msgid="8985999749231486569">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」正在執行中"</string>
<string name="app_running_notification_text" msgid="5120815883400228566">"輕觸即可瞭解詳情或停止應用程式。"</string>
<string name="ok" msgid="2646370155170753815">"確定"</string>
<string name="cancel" msgid="6908697720451760115">"取消"</string>
@@ -1441,7 +1439,7 @@
<string name="fast_scroll_numeric_alphabet" msgid="2529539945421557329">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="alert_windows_notification_channel_group_name" msgid="6063891141815714246">"在其他應用程式上面顯示"</string>
<string name="alert_windows_notification_channel_name" msgid="3437528564303192620">"「<xliff:g id="NAME">%s</xliff:g>」在其他應用程式上顯示內容"</string>
- <string name="alert_windows_notification_title" msgid="6331662751095228536">"「<xliff:g id="NAME">%s</xliff:g>」正在其他應用程式上顯示內容"</string>
+ <string name="alert_windows_notification_title" msgid="6331662751095228536">"「<xliff:g id="NAME">%s</xliff:g>」正重疊顯示在其他應用程式上方"</string>
<string name="alert_windows_notification_message" msgid="6538171456970725333">"如果你不想讓「<xliff:g id="NAME">%s</xliff:g>」使用這項功能,請輕觸開啟設定頁面,然後停用此功能。"</string>
<string name="alert_windows_notification_turn_off_action" msgid="7805857234839123780">"關閉"</string>
<string name="ext_media_checking_notification_title" msgid="8299199995416510094">"正在檢查 <xliff:g id="NAME">%s</xliff:g>…"</string>
@@ -1767,12 +1765,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"下次輕觸無障礙工具按鈕時,就會開啟這項功能"</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"下次使用這個捷徑時,就會開啟這項功能。請用 2 指從螢幕底部向上滑動並快速放開。"</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"下次使用這個捷徑時,就會開啟這項功能。請用 3 指從螢幕底部向上滑動並快速放開。"</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"放大"</string>
<string name="user_switched" msgid="7249833311585228097">"目前的使用者是 <xliff:g id="NAME">%1$s</xliff:g>。"</string>
<string name="user_switching_message" msgid="1912993630661332336">"正在切換至<xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2436,17 +2431,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"運作方式"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"待處理…"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"重新設定指紋解鎖"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"系統無法再辨識「<xliff:g id="FINGERPRINT">%s</xliff:g>」。"</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"系統無法再辨識「<xliff:g id="FINGERPRINT_0">%1$s</xliff:g>」和「<xliff:g id="FINGERPRINT_1">%2$s</xliff:g>」。"</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"系統無法再辨識「<xliff:g id="FINGERPRINT">%s</xliff:g>」,請重新設定指紋解鎖。"</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"系統無法再辨識「<xliff:g id="FINGERPRINT_0">%1$s</xliff:g>」和「<xliff:g id="FINGERPRINT_1">%2$s</xliff:g>」,請重新設定指紋解鎖。"</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"重新設定人臉解鎖"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"系統無法再辨識你的臉部模型,請重新設定人臉解鎖。"</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"設定"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"暫時不要"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"<xliff:g id="USER_NAME">%s</xliff:g>的鬧鐘"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 695dc98dd3b8..d378b7c5d466 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -265,8 +265,6 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"Umbiko wephutha"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Phothula isikhathi"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Isithombe-skrini"</string>
- <!-- no translation found for identity_check_biometric_prompt_description (5810195983015866727) -->
- <skip />
<string name="bugreport_title" msgid="8549990811777373050">"Umbiko wephutha"</string>
<string name="bugreport_message" msgid="5212529146119624326">"Lokhu kuzoqoqa ulwazi mayelana nesimo samanje sedivayisi yakho, ukuthumela imilayezo ye-imeyili. Kuzothatha isikhathi esincane kusuka ekuqaleni umbiko wesiphazamiso uze ulungele ukuthunyelwa; sicela ubekezele."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"Umbiko obandakanyayo"</string>
@@ -1767,12 +1765,9 @@
<skip />
<!-- no translation found for accessibility_gesture_3finger_prompt_text (77745752309056152) -->
<skip />
- <!-- no translation found for accessibility_button_instructional_text (6831154884557881996) -->
- <skip />
- <!-- no translation found for accessibility_gesture_instructional_text (4133877896011098550) -->
- <skip />
- <!-- no translation found for accessibility_gesture_3finger_instructional_text (1124458279366968154) -->
- <skip />
+ <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"Isakhi sizovuleka ngokulandelayo uma uthepha inkinobho yokufinyeleleka"</string>
+ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"Lesi sakhi sizovuleka ngokulandelayo uma usebenzisa lesi sinqamuleli. Swayiphela phezulu ngeminwe engu-2 kusukela ngaphansi kwesikrini sakho uphinde udedele ngokushesha."</string>
+ <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"Lesi sakhi sizovuleka ngokulandelayo uma usebenzisa lesi sinqamuleli. Swayiphela phezulu ngeminwe engu-3 kusukela ngaphansi kwesikrini sakho uphinde udedele ngokushesha."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Ukukhuliswa"</string>
<string name="user_switched" msgid="7249833311585228097">"Umsebenzisi wamanje <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="1912993630661332336">"Ishintshela ku-<xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2436,17 +2431,12 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Indlela esebenza ngayo"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Ilindile..."</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Setha Ukuvula ngesigxivizo somunwe futhi"</string>
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (5851784577768803510) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7925203589860744456) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (1824812666549916586) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (5974657382960155099) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"I-<xliff:g id="FINGERPRINT">%s</xliff:g> angeke isaziwa."</string>
+ <string name="fingerprint_dangling_notification_msg_2" msgid="7925203589860744456">"I-<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> kanye ne-<xliff:g id="FINGERPRINT_1">%2$s</xliff:g> angeke isaziwa."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="1824812666549916586">"I-<xliff:g id="FINGERPRINT">%s</xliff:g> angeke isaziwa. Setha Ukuvula Ngesigxivizo Somunwe futhi."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="5974657382960155099">"I-<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> kanye ne-<xliff:g id="FINGERPRINT_1">%2$s</xliff:g> angeke isaziwa. Setha Ukuvula Ngesigxivizo Somunwe futhi."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"Setha Ukuvula Ngobuso futhi"</string>
- <!-- no translation found for face_dangling_notification_msg (746235263598985384) -->
- <skip />
+ <string name="face_dangling_notification_msg" msgid="746235263598985384">"Imodeli yobuso yakho angeke isabonwa. Setha Ukuvula Ngobuso futhi."</string>
<string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Setha"</string>
<string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Hhayi manje"</string>
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"I-alamu ka-<xliff:g id="USER_NAME">%s</xliff:g>"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 4892f59bd9fb..0975eda3f9ff 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -4304,7 +4304,7 @@
<attr name="settingsActivity" format="string" />
<!-- Component name of an activity that allows the user to modify
on-screen keyboards variants (e.g. different language or layout) for this service. -->
- <!-- @FlaggedApi("android.view.inputmethod.ime_switcher_revamp") -->
+ <!-- @FlaggedApi("android.view.inputmethod.ime_switcher_revamp_api") -->
<attr name="languageSettingsActivity" format="string"/>
<!-- Set to true in all of the configurations for which this input
method should be considered an option as the default. -->
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index f94c8ab0350e..2e3dbda5e41c 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1052,6 +1052,19 @@
<!-- The font weight adjustment value has changed. Used to reflect the user increasing font
weight. -->
<flag name="fontWeightAdjustment" value="0x10000000" />
+ <!-- The assets paths have changed. For example a runtime overlay is installed and enabled.
+ Corresponds to {@link android.content.pm.ActivityInfo#CONFIG_ASSETS_PATHS}. -->
+ <flag name="assetsPaths" value="0x80000000" />
+ <!-- This is probably not the flag you want, the resources compiler supports a less
+ dangerous version of it, 'allKnown', that only suppresses all currently existing
+ configuration change restarts depending on your target SDK rather than whatever the
+ latest SDK supports, allowing the application to work with resources on future Platform
+ versions.
+ Activity doesn't use Android Resources at all and doesn't need to be restarted on any
+ configuration changes. This overrides all other flags, and this is recommended to be
+ used individually. Corresponds to
+ {@link android.content.pm.ActivityInfo#CONFIG_RESOURCES_UNUSED}. -->
+ <flag name="resourcesUnused" value="0x8000000" />
</attr>
<!-- Indicate that the activity can be launched as the embedded child of another
diff --git a/core/res/res/values/public-staging.xml b/core/res/res/values/public-staging.xml
index b64334f7f95a..b74b41c666c8 100644
--- a/core/res/res/values/public-staging.xml
+++ b/core/res/res/values/public-staging.xml
@@ -114,7 +114,7 @@
<public name="optional"/>
<!-- @FlaggedApi("android.media.tv.flags.enable_ad_service_fw") -->
<public name="adServiceTypes" />
- <!-- @FlaggedApi("android.view.inputmethod.ime_switcher_revamp") -->
+ <!-- @FlaggedApi("android.view.inputmethod.ime_switcher_revamp_api") -->
<public name="languageSettingsActivity"/>
<!-- @FlaggedApi("android.service.controls.flags.Flags.FLAG_HOME_PANEL_DREAM") -->
<public name="dreamCategory"/>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 6b71f97e3f17..46b154163224 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -6534,4 +6534,23 @@ ul.</string>
<string name="bg_user_sound_notification_button_mute">Mute</string>
<!-- Notification text to mute the sound from the background user [CHAR LIMIT=NOTIF_BODY]-->
<string name="bg_user_sound_notification_message">Tap to mute sound</string>
+
+ <!-- User visible title for the keyboard shortcut that takes the user to the browser app. [CHAR LIMIT=70] -->
+ <string name="keyboard_shortcut_group_applications_browser">Browser</string>
+ <!-- User visible title for the keyboard shortcut that takes the user to the contacts app. [CHAR LIMIT=70] -->
+ <string name="keyboard_shortcut_group_applications_contacts">Contacts</string>
+ <!-- User visible title for the keyboard shortcut that takes the user to the email app. [CHAR LIMIT=70] -->
+ <string name="keyboard_shortcut_group_applications_email">Email</string>
+ <!-- User visible title for the keyboard shortcut that takes the user to the SMS messaging app. [CHAR LIMIT=70] -->
+ <string name="keyboard_shortcut_group_applications_sms">SMS</string>
+ <!-- User visible title for the keyboard shortcut that takes the user to the music app. [CHAR LIMIT=70] -->
+ <string name="keyboard_shortcut_group_applications_music">Music</string>
+ <!-- User visible title for the keyboard shortcut that takes the user to the calendar app. [CHAR LIMIT=70] -->
+ <string name="keyboard_shortcut_group_applications_calendar">Calendar</string>
+ <!-- User visible title for the keyboard shortcut that takes the user to the calculator app. [CHAR LIMIT=70] -->
+ <string name="keyboard_shortcut_group_applications_calculator">Calculator</string>
+ <!-- User visible title for the keyboard shortcut that takes the user to the maps app. [CHAR LIMIT=70] -->
+ <string name="keyboard_shortcut_group_applications_maps">Maps</string>
+ <!-- User visible title for the keyboard shortcut group containing system-wide application launch shortcuts. [CHAR-LIMIT=70] -->
+ <string name="keyboard_shortcut_group_applications">Applications</string>
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index d25f59d7c488..c50b961f74cd 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -5561,4 +5561,15 @@
<java-symbol type="string" name="bg_user_sound_notification_button_switch_user" />
<java-symbol type="string" name="bg_user_sound_notification_button_mute" />
<java-symbol type="string" name="bg_user_sound_notification_message" />
+
+ <!-- Keyboard Shortcut default category names. -->
+ <java-symbol type="string" name="keyboard_shortcut_group_applications_browser" />
+ <java-symbol type="string" name="keyboard_shortcut_group_applications_calculator" />
+ <java-symbol type="string" name="keyboard_shortcut_group_applications_calendar" />
+ <java-symbol type="string" name="keyboard_shortcut_group_applications_contacts" />
+ <java-symbol type="string" name="keyboard_shortcut_group_applications_email" />
+ <java-symbol type="string" name="keyboard_shortcut_group_applications_maps" />
+ <java-symbol type="string" name="keyboard_shortcut_group_applications_music" />
+ <java-symbol type="string" name="keyboard_shortcut_group_applications_sms" />
+ <java-symbol type="string" name="keyboard_shortcut_group_applications" />
</resources>
diff --git a/core/res/res/xml/power_profile.xml b/core/res/res/xml/power_profile.xml
index fc63657f04d0..f67ad3f5575e 100644
--- a/core/res/res/xml/power_profile.xml
+++ b/core/res/res/xml/power_profile.xml
@@ -33,14 +33,14 @@
There must be one of these for each display, labeled:
ambient.on.display0, ambient.on.display1, etc...
- Each display suffix number should match it's ordinal in its display device config.
+ Each display suffix number should match its ordinal in its display device config.
-->
<item name="ambient.on.display0">0.1</item> <!-- ~100mA -->
<!-- Average battery current draw of display0 while on without backlight.
There must be one of these for each display, labeled:
screen.on.display0, screen.on.display1, etc...
- Each display suffix number should match it's ordinal in its display device config.
+ Each display suffix number should match its ordinal in its display device config.
-->
<item name="screen.on.display0">0.1</item> <!-- ~100mA -->
<!-- Average battery current draw of the backlight at full brightness.
@@ -50,7 +50,7 @@
There must be one of these for each display, labeled:
screen.full.display0, screen.full.display1, etc...
- Each display suffix number should match it's ordinal in its display device config.
+ Each display suffix number should match its ordinal in its display device config.
-->
<item name="screen.full.display0">0.1</item> <!-- ~100mA -->
diff --git a/core/tests/InputMethodCoreTests/src/android/view/inputmethod/InputMethodInfoTest.java b/core/tests/InputMethodCoreTests/src/android/view/inputmethod/InputMethodInfoTest.java
index 36ab0d4b0868..ce85a76f478d 100644
--- a/core/tests/InputMethodCoreTests/src/android/view/inputmethod/InputMethodInfoTest.java
+++ b/core/tests/InputMethodCoreTests/src/android/view/inputmethod/InputMethodInfoTest.java
@@ -70,7 +70,7 @@ public class InputMethodInfoTest {
assertThat(imi.supportsInlineSuggestionsWithTouchExploration(), is(false));
assertThat(imi.supportsStylusHandwriting(), is(false));
assertThat(imi.createStylusHandwritingSettingsActivityIntent(), equalTo(null));
- if (Flags.imeSwitcherRevamp()) {
+ if (Flags.imeSwitcherRevampApi()) {
assertThat(imi.createImeLanguageSettingsActivityIntent(), equalTo(null));
}
}
diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
index f87a9e2b3643..e8a0762f70c0 100644
--- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
+++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
@@ -25,8 +25,6 @@ import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
-import static com.android.window.flags.Flags.FLAG_ACTIVITY_WINDOW_INFO_FLAG;
-
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
@@ -810,7 +808,6 @@ public class ActivityThreadTest {
@Test
public void testActivityWindowInfoChanged_activityLaunch() {
- mSetFlagsRule.enableFlags(FLAG_ACTIVITY_WINDOW_INFO_FLAG);
ClientTransactionListenerController.getInstance().registerActivityWindowInfoChangedListener(
mActivityWindowInfoListener);
@@ -825,7 +822,6 @@ public class ActivityThreadTest {
@Test
public void testActivityWindowInfoChanged_activityRelaunch() {
- mSetFlagsRule.enableFlags(FLAG_ACTIVITY_WINDOW_INFO_FLAG);
ClientTransactionListenerController.getInstance().registerActivityWindowInfoChangedListener(
mActivityWindowInfoListener);
@@ -866,7 +862,6 @@ public class ActivityThreadTest {
@Test
public void testActivityWindowInfoChanged_activityConfigurationChanged() {
- mSetFlagsRule.enableFlags(FLAG_ACTIVITY_WINDOW_INFO_FLAG);
ClientTransactionListenerController.getInstance().registerActivityWindowInfoChangedListener(
mActivityWindowInfoListener);
diff --git a/core/tests/coretests/src/android/app/servertransaction/ClientTransactionListenerControllerTest.java b/core/tests/coretests/src/android/app/servertransaction/ClientTransactionListenerControllerTest.java
index 0b270d485b97..d2a444f0d0df 100644
--- a/core/tests/coretests/src/android/app/servertransaction/ClientTransactionListenerControllerTest.java
+++ b/core/tests/coretests/src/android/app/servertransaction/ClientTransactionListenerControllerTest.java
@@ -53,8 +53,6 @@ import android.window.WindowTokenClient;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
-import com.android.window.flags.Flags;
-
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -167,8 +165,6 @@ public class ClientTransactionListenerControllerTest {
@Test
public void testActivityWindowInfoChangedListener() {
- mSetFlagsRule.enableFlags(Flags.FLAG_ACTIVITY_WINDOW_INFO_FLAG);
-
mController.registerActivityWindowInfoChangedListener(mActivityWindowInfoListener);
final ActivityWindowInfo activityWindowInfo = new ActivityWindowInfo();
activityWindowInfo.set(true /* isEmbedded */, new Rect(0, 0, 1000, 2000),
diff --git a/core/tests/coretests/src/android/inputmethodservice/ImsConfigurationTrackerTest.java b/core/tests/coretests/src/android/inputmethodservice/ImsConfigurationTrackerTest.java
index 064439e9b113..6998c32978c1 100644
--- a/core/tests/coretests/src/android/inputmethodservice/ImsConfigurationTrackerTest.java
+++ b/core/tests/coretests/src/android/inputmethodservice/ImsConfigurationTrackerTest.java
@@ -24,6 +24,7 @@ import static org.junit.Assert.assertTrue;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
+import android.platform.test.annotations.RequiresFlagsEnabled;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -74,4 +75,33 @@ public class ImsConfigurationTrackerTest {
assertFalse("IME shouldn't restart since it handles configChanges",
didReset.get());
}
+
+ @Test
+ @RequiresFlagsEnabled(android.content.res.Flags.FLAG_HANDLE_ALL_CONFIG_CHANGES)
+ public void testShouldImeRestart_handleResourceUnused() throws Exception {
+ Configuration config = mContext.getResources().getConfiguration();
+ mImsConfigTracker.onInitialize(0 /* handledConfigChanges */);
+ mImsConfigTracker.onBindInput(mContext.getResources());
+ Configuration newConfig = new Configuration(config);
+
+ final AtomicBoolean didReset = new AtomicBoolean();
+ Runnable resetStateRunner = () -> didReset.set(true);
+
+ mImsConfigTracker.onConfigurationChanged(newConfig, resetStateRunner);
+ assertFalse("IME shouldn't restart if config hasn't changed",
+ didReset.get());
+
+ // Screen density changed but IME doesn't handle configChanges
+ newConfig.densityDpi = 99;
+ mImsConfigTracker.onConfigurationChanged(newConfig, resetStateRunner);
+ assertTrue("IME should restart for unhandled configChanges",
+ didReset.get());
+
+ didReset.set(false);
+ // opt-in IME to handle all configuration changes.
+ mImsConfigTracker.setHandledConfigChanges(ActivityInfo.CONFIG_RESOURCES_UNUSED);
+ mImsConfigTracker.onConfigurationChanged(newConfig, resetStateRunner);
+ assertFalse("IME shouldn't restart since it handles configChanges",
+ didReset.get());
+ }
}
diff --git a/core/tests/coretests/src/android/view/ViewFrameRateTest.java b/core/tests/coretests/src/android/view/ViewFrameRateTest.java
index c01b51dcade8..b68ff78107ca 100644
--- a/core/tests/coretests/src/android/view/ViewFrameRateTest.java
+++ b/core/tests/coretests/src/android/view/ViewFrameRateTest.java
@@ -29,11 +29,9 @@ import static android.view.flags.Flags.FLAG_VIEW_VELOCITY_API;
import static android.view.flags.Flags.toolkitFrameRateBySizeReadOnly;
import static android.view.flags.Flags.toolkitFrameRateDefaultNormalReadOnly;
import static android.view.flags.Flags.toolkitFrameRateSmallUsesPercentReadOnly;
-import static android.view.flags.Flags.toolkitFrameRateVelocityMappingReadOnly;
import static junit.framework.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import android.annotation.NonNull;
@@ -100,9 +98,8 @@ public class ViewFrameRateTest {
}
@Test
- @RequiresFlagsEnabled({FLAG_VIEW_VELOCITY_API,
- FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY})
- public void frameRateChangesWhenContentMoves() throws Throwable {
+ @RequiresFlagsEnabled(FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY)
+ public void highHintWhenContentMoves() throws Throwable {
if (!ViewProperties.vrr_enabled().orElse(true)) {
return;
}
@@ -110,21 +107,15 @@ public class ViewFrameRateTest {
mActivityRule.runOnUiThread(() -> {
mMovingView.offsetLeftAndRight(100);
runAfterDraw(() -> {
- if (toolkitFrameRateVelocityMappingReadOnly()) {
- float frameRate = mViewRoot.getLastPreferredFrameRate();
- assertTrue(frameRate > 0);
- } else {
- assertEquals(FRAME_RATE_CATEGORY_HIGH,
- mViewRoot.getLastPreferredFrameRateCategory());
- }
+ assertEquals(FRAME_RATE_CATEGORY_HIGH_HINT,
+ mViewRoot.getLastPreferredFrameRateCategory());
});
});
waitForAfterDraw();
}
@Test
- @RequiresFlagsEnabled({FLAG_VIEW_VELOCITY_API,
- FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY})
+ @RequiresFlagsEnabled(FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY)
public void inputMethodWithContentMoves() throws Throwable {
if (!ViewProperties.vrr_enabled().orElse(true)) {
return;
@@ -136,6 +127,8 @@ public class ViewFrameRateTest {
final WindowManager.LayoutParams attrs = mViewRoot.mWindowAttributes;
attrs.type = TYPE_INPUT_METHOD;
instrumentation.runOnMainSync(() -> {
+ attrs.width = 1;
+ attrs.height = 1;
mViewRoot.setLayoutParams(attrs, false);
});
instrumentation.waitForIdleSync();
@@ -147,14 +140,13 @@ public class ViewFrameRateTest {
mActivityRule.runOnUiThread(() -> {
mMovingView.offsetLeftAndRight(100);
runAfterDraw(() -> {
- if (toolkitFrameRateVelocityMappingReadOnly()) {
- float frameRate = mViewRoot.getLastPreferredFrameRate();
- // frame rate shouldn't be boost with TYPE_INPUT_METHOD window type
- assertTrue(frameRate == 0);
- } else {
- assertEquals(FRAME_RATE_CATEGORY_HIGH,
- mViewRoot.getLastPreferredFrameRateCategory());
- }
+ int expected = toolkitFrameRateBySizeReadOnly()
+ ? FRAME_RATE_CATEGORY_LOW : FRAME_RATE_CATEGORY_NORMAL;
+ float frameRate = mViewRoot.getLastPreferredFrameRate();
+ // frame rate shouldn't be boost with TYPE_INPUT_METHOD window type
+ assertTrue(frameRate == 0);
+ assertEquals(expected,
+ mViewRoot.getLastPreferredFrameRateCategory());
});
});
waitForAfterDraw();
@@ -177,7 +169,7 @@ public class ViewFrameRateTest {
@Test
- @RequiresFlagsEnabled(FLAG_VIEW_VELOCITY_API)
+ @RequiresFlagsEnabled(FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY)
public void highHintWhenActionMove() throws Throwable {
if (!ViewProperties.vrr_enabled().orElse(true)) {
return;
@@ -227,62 +219,59 @@ public class ViewFrameRateTest {
move.setSource(InputDevice.SOURCE_TOUCHSCREEN);
instrumentation.sendPointerSync(move);
- // We should continue to enable touch boost even when GTE compatibility is present.
+ // Should continue to enable touch boost.
mActivityRule.runOnUiThread(() -> {
mMovingView.offsetLeftAndRight(10);
assertTrue(mViewRoot.getIsTouchBoosting());
});
- now = SystemClock.uptimeMillis();
- MotionEvent up = MotionEvent.obtain(
- now, // downTime
- now, // eventTime
- MotionEvent.ACTION_UP, // action
- position[0], // x
- position[1], // y
- 0 // metaState
- );
- up.setSource(InputDevice.SOURCE_TOUCHSCREEN);
- instrumentation.sendPointerSync(up);
-
- // No touch boost when there is no ongoing pressed gesture.
- mActivityRule.runOnUiThread(() -> {
- mMovingView.offsetLeftAndRight(10);
- assertFalse(mViewRoot.getIsTouchBoosting());
- });
-
down.recycle();
move.recycle();
- up.recycle();
}
+ // When the size of a View is changed, we should boost the frame rate.
@Test
- @RequiresFlagsEnabled(FLAG_VIEW_VELOCITY_API)
- public void frameBoostDisable() throws Throwable {
+ @RequiresFlagsEnabled(FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY)
+ public void highHintWhenSizeChanged() throws Throwable {
if (!ViewProperties.vrr_enabled().orElse(true)) {
return;
}
+ waitForFrameRateCategoryToSettle();
+ assertEquals(FRAME_RATE_CATEGORY_LOW,
+ mViewRoot.getLastPreferredFrameRateCategory());
+
+ int width = mMovingView.getWidth();
+ int height = mMovingView.getHeight();
+
+ ViewGroup.LayoutParams params = mMovingView.getLayoutParams();
+ params.width = width * 2;
+ params.height = height * 2;
+
+ // frame rate category should be HIGH_HINT when the size is changed
mActivityRule.runOnUiThread(() -> {
- long now = SystemClock.uptimeMillis();
- MotionEvent down = MotionEvent.obtain(
- /* downTime */ now,
- /* eventTime */ now,
- /* action */ MotionEvent.ACTION_DOWN,
- /* x */ 0f,
- /* y */ 0f,
- /* metaState */ 0
- );
- mActivity.dispatchTouchEvent(down);
- mMovingView.offsetLeftAndRight(10);
- });
- mActivityRule.runOnUiThread(() -> {
- mMovingView.invalidate();
+ mMovingView.setLayoutParams(params);
+ runAfterDraw(() -> {
+ assertTrue(mMovingView.getWidth() > width);
+ assertTrue(mMovingView.getHeight() > height);
+ assertEquals(FRAME_RATE_CATEGORY_HIGH_HINT,
+ mViewRoot.getLastPreferredFrameRateCategory());
+ });
});
+ waitForAfterDraw();
+ // set it back to the original size
+ params.width = width;
+ params.height = height;
mActivityRule.runOnUiThread(() -> {
- assertFalse(mViewRoot.getIsTouchBoosting());
- assertFalse(mViewRoot.getIsFrameRateBoosting());
+ mMovingView.setLayoutParams(params);
+ runAfterDraw(() -> {
+ assertEquals(width, mMovingView.getWidth());
+ assertEquals(height, mMovingView.getHeight());
+ assertEquals(FRAME_RATE_CATEGORY_HIGH_HINT,
+ mViewRoot.getLastPreferredFrameRateCategory());
+ });
});
+ waitForAfterDraw();
}
@Test
@@ -804,6 +793,12 @@ public class ViewFrameRateTest {
down.setSource(InputDevice.SOURCE_TOUCHSCREEN);
instrumentation.sendPointerSync(down);
assertEquals(FRAME_RATE_CATEGORY_HIGH_HINT, mViewRoot.getLastPreferredFrameRateCategory());
+
+ // Should still be boost with position changed
+ mActivityRule.runOnUiThread(() -> {
+ mMovingView.offsetLeftAndRight(10);
+ assertTrue(mViewRoot.getIsTouchBoosting());
+ });
}
@LargeTest
diff --git a/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java b/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
index d4482f243939..9ae96a0fc9d8 100644
--- a/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
+++ b/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
@@ -348,12 +348,16 @@ public class WindowOnBackInvokedDispatcherTest {
waitForIdle();
verify(mCallback1).onBackStarted(any(BackEvent.class));
+ assertTrue(mDispatcher.mProgressAnimator.isBackAnimationInProgress());
mDispatcher.unregisterOnBackInvokedCallback(mCallback1);
waitForIdle();
verify(mCallback1).onBackCancelled();
verify(mWindowSession).setOnBackInvokedCallbackInfo(Mockito.eq(mWindow), isNull());
+ // Verify that ProgressAnimator is reset (and thus does not cause further callback event
+ // dispatching)
+ assertFalse(mDispatcher.mProgressAnimator.isBackAnimationInProgress());
}
@Test
diff --git a/core/tests/overlaytests/handle_config_change/Android.bp b/core/tests/overlaytests/handle_config_change/Android.bp
new file mode 100644
index 000000000000..2b31d0adab17
--- /dev/null
+++ b/core/tests/overlaytests/handle_config_change/Android.bp
@@ -0,0 +1,45 @@
+// Copyright (C) 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+ default_team: "trendy_team_android_resources",
+}
+
+java_test_host {
+ name: "HandleConfigChangeHostTests",
+ srcs: ["src/**/*.java"],
+ libs: [
+ "tradefed",
+ "compatibility-host-util",
+ ],
+ static_libs: [
+ "compatibility-host-util-axt",
+ "flag-junit-host",
+ "android.content.res.flags-aconfig-java-host",
+ ],
+ test_suites: [
+ "device-tests",
+ ],
+ // All APKs required by the tests
+ data: [
+ ":OverlayResApp",
+ ],
+ per_testcase_directory: true,
+}
diff --git a/core/tests/overlaytests/handle_config_change/AndroidTest.xml b/core/tests/overlaytests/handle_config_change/AndroidTest.xml
new file mode 100644
index 000000000000..05ea03686484
--- /dev/null
+++ b/core/tests/overlaytests/handle_config_change/AndroidTest.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2024 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<configuration description="Config for the handle config change test cases">
+ <option name="test-tag" value="HandleConfigChangeHostTests" />
+ <option name="test-suite-tag" value="apct" />
+
+ <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
+ <option name="force-skip-system-props" value="true" />
+ <option name="set-global-setting" key="verifier_engprod" value="1" />
+ <option name="set-global-setting" key="verifier_verify_adb_installs" value="0" />
+ <option name="restore-settings" value="true" />
+ </target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="OverlayResApp.apk" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.HostTest">
+ <option name="class" value="com.android.overlaytest.HandleConfigChangeHostTests" />
+ </test>
+</configuration>
diff --git a/core/tests/overlaytests/handle_config_change/src/com/android/overlaytest/HandleConfigChangeHostTests.java b/core/tests/overlaytests/handle_config_change/src/com/android/overlaytest/HandleConfigChangeHostTests.java
new file mode 100644
index 000000000000..e91716ab04b3
--- /dev/null
+++ b/core/tests/overlaytests/handle_config_change/src/com/android/overlaytest/HandleConfigChangeHostTests.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.overlaytest;
+
+import android.content.res.Flags;
+import android.platform.test.annotations.AppModeFull;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.host.HostFlagsValueProvider;
+
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+@AppModeFull
+public class HandleConfigChangeHostTests extends BaseHostJUnit4Test {
+ @Rule
+ public final CheckFlagsRule mCheckFlagsRule =
+ HostFlagsValueProvider.createCheckFlagsRule(this::getDevice);
+ private static final String DEVICE_TEST_PKG1 = "com.android.overlaytest.overlayresapp";
+ private static final String DEVICE_TEST_CLASS = "OverlayResTest";
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_HANDLE_ALL_CONFIG_CHANGES)
+ public void testOverlayRes() throws Exception {
+ runDeviceTests(DEVICE_TEST_PKG1, DEVICE_TEST_PKG1 + "." + DEVICE_TEST_CLASS,
+ "overlayRes_onConfigurationChanged");
+ }
+}
diff --git a/core/tests/overlaytests/handle_config_change/test-apps/OverlayResApp/Android.bp b/core/tests/overlaytests/handle_config_change/test-apps/OverlayResApp/Android.bp
new file mode 100644
index 000000000000..e0f101229080
--- /dev/null
+++ b/core/tests/overlaytests/handle_config_change/test-apps/OverlayResApp/Android.bp
@@ -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 {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "OverlayResApp",
+ srcs: ["src/**/*.java"],
+ resource_dirs: ["res"],
+ platform_apis: true,
+ certificate: "platform",
+
+ static_libs: [
+ "androidx.annotation_annotation",
+ "androidx.test.rules",
+ "androidx.test.core",
+ "compatibility-device-util-axt",
+ "truth",
+ ],
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ ],
+ test_suites: [
+ "device-tests",
+ ],
+
+ manifest: "AndroidManifest.xml",
+}
diff --git a/core/tests/overlaytests/handle_config_change/test-apps/OverlayResApp/AndroidManifest.xml b/core/tests/overlaytests/handle_config_change/test-apps/OverlayResApp/AndroidManifest.xml
new file mode 100644
index 000000000000..617e8796317a
--- /dev/null
+++ b/core/tests/overlaytests/handle_config_change/test-apps/OverlayResApp/AndroidManifest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2024 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.overlaytest.overlayresapp"
+ xmlns:tools="http://schemas.android.com/tools">
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ <activity
+ android:name=".OverlayResActivity"
+ android:exported="false"
+ android:configChanges="assetsPaths">
+ </activity>
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.overlaytest.overlayresapp" />
+
+</manifest>
diff --git a/core/tests/overlaytests/handle_config_change/test-apps/OverlayResApp/res/values/integers.xml b/core/tests/overlaytests/handle_config_change/test-apps/OverlayResApp/res/values/integers.xml
new file mode 100644
index 000000000000..493333f8268b
--- /dev/null
+++ b/core/tests/overlaytests/handle_config_change/test-apps/OverlayResApp/res/values/integers.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2024 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources>
+ <integer name="test_integer">0</integer>
+</resources> \ No newline at end of file
diff --git a/core/tests/overlaytests/handle_config_change/test-apps/OverlayResApp/res/values/strings.xml b/core/tests/overlaytests/handle_config_change/test-apps/OverlayResApp/res/values/strings.xml
new file mode 100644
index 000000000000..72820d37fdc7
--- /dev/null
+++ b/core/tests/overlaytests/handle_config_change/test-apps/OverlayResApp/res/values/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2024 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources>
+ <string name="app_name">My Application</string>
+ <string name="test_string">Test String</string>
+</resources> \ No newline at end of file
diff --git a/core/tests/overlaytests/handle_config_change/test-apps/OverlayResApp/src/com/android/overlaytest/overlayresapp/OverlayResActivity.java b/core/tests/overlaytests/handle_config_change/test-apps/OverlayResApp/src/com/android/overlaytest/overlayresapp/OverlayResActivity.java
new file mode 100644
index 000000000000..96143ae4e1e1
--- /dev/null
+++ b/core/tests/overlaytests/handle_config_change/test-apps/OverlayResApp/src/com/android/overlaytest/overlayresapp/OverlayResActivity.java
@@ -0,0 +1,50 @@
+/*
+ * 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.overlaytest.overlayresapp;
+
+import android.app.Activity;
+import android.content.res.Configuration;
+import android.os.Bundle;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+/**
+ * A test activity to verify that the assets paths configuration changes are received if the
+ * overlay targeting state is changed.
+ */
+public class OverlayResActivity extends Activity {
+ private Runnable mConfigurationChangedCallback;
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ public void onConfigurationChanged(@NonNull Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ final Runnable callback = mConfigurationChangedCallback;
+ if (callback != null) {
+ callback.run();
+ }
+ }
+
+ /** Registers the callback of onConfigurationChanged. */
+ public void setConfigurationChangedCallback(Runnable callback) {
+ mConfigurationChangedCallback = callback;
+ }
+}
diff --git a/core/tests/overlaytests/handle_config_change/test-apps/OverlayResApp/src/com/android/overlaytest/overlayresapp/OverlayResTest.java b/core/tests/overlaytests/handle_config_change/test-apps/OverlayResApp/src/com/android/overlaytest/overlayresapp/OverlayResTest.java
new file mode 100644
index 000000000000..1c377192f0ea
--- /dev/null
+++ b/core/tests/overlaytests/handle_config_change/test-apps/OverlayResApp/src/com/android/overlaytest/overlayresapp/OverlayResTest.java
@@ -0,0 +1,148 @@
+/*
+ * 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.overlaytest.overlayresapp;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static junit.framework.Assert.assertNotNull;
+
+import static org.junit.Assert.fail;
+
+import android.content.Context;
+import android.content.om.FabricatedOverlay;
+import android.content.om.OverlayInfo;
+import android.content.om.OverlayManager;
+import android.content.om.OverlayManagerTransaction;
+import android.content.res.Resources;
+import android.os.UserHandle;
+import android.util.TypedValue;
+
+import androidx.test.ext.junit.rules.ActivityScenarioRule;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(JUnit4.class)
+public class OverlayResTest {
+ // Default timeout value
+ private static final long TIMEOUT_MS = TimeUnit.SECONDS.toMillis(5);
+ private static final String TEST_OVERLAY_NAME = "Test";
+ private static final String TEST_RESOURCE_INTEGER = "integer/test_integer";
+ private static final String TEST_RESOURCE_STRING = "string/test_string";
+ private static final int TEST_INTEGER = 0;
+ private static final int TEST_FRRO_INTEGER = 1;
+ private static final String TEST_STRING = "Test String";
+ private static final String TEST_FRRO_STRING = "FRRO Test String";
+ private OverlayResActivity mActivity;
+ private Context mContext;
+ private OverlayManager mOverlayManager;
+ private int mUserId;
+ private UserHandle mUserHandle;
+
+ @Rule
+ public ActivityScenarioRule<OverlayResActivity> mActivityScenarioRule =
+ new ActivityScenarioRule<>(OverlayResActivity.class);
+
+ @Before
+ public void setUp() {
+ mActivityScenarioRule.getScenario().onActivity(activity -> {
+ assertThat(activity).isNotNull();
+ mActivity = activity;
+ });
+ mContext = mActivity.getApplicationContext();
+ mOverlayManager = mContext.getSystemService(OverlayManager.class);
+ mUserId = UserHandle.myUserId();
+ mUserHandle = UserHandle.of(mUserId);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ final OverlayManagerTransaction.Builder cleanUp = new OverlayManagerTransaction.Builder();
+ mOverlayManager.getOverlayInfosForTarget(mContext.getPackageName(), mUserHandle).forEach(
+ info -> {
+ if (info.isFabricated()) {
+ cleanUp.unregisterFabricatedOverlay(info.getOverlayIdentifier());
+ }
+ });
+ mOverlayManager.commit(cleanUp.build());
+
+ }
+
+ @Test
+ public void overlayRes_onConfigurationChanged() throws Exception {
+ final CountDownLatch latch1 = new CountDownLatch(1);
+ mActivity.setConfigurationChangedCallback(() -> {
+ Resources r = mActivity.getApplicationContext().getResources();
+ assertThat(r.getInteger(R.integer.test_integer)).isEqualTo(TEST_FRRO_INTEGER);
+ assertThat(r.getString(R.string.test_string)).isEqualTo(TEST_FRRO_STRING);
+ latch1.countDown();
+ });
+
+ // Create and enable FRRO
+ final FabricatedOverlay overlay = new FabricatedOverlay.Builder(
+ mContext.getPackageName(), TEST_OVERLAY_NAME, mContext.getPackageName())
+ .setResourceValue(TEST_RESOURCE_INTEGER, TypedValue.TYPE_INT_DEC, TEST_FRRO_INTEGER)
+ .setResourceValue(TEST_RESOURCE_STRING, TypedValue.TYPE_STRING, TEST_FRRO_STRING)
+ .build();
+
+ mOverlayManager.commit(new OverlayManagerTransaction.Builder()
+ .registerFabricatedOverlay(overlay)
+ .build());
+
+ OverlayInfo info = mOverlayManager.getOverlayInfo(overlay.getIdentifier(), mUserHandle);
+ assertNotNull(info);
+ assertThat(info.isEnabled()).isFalse();
+
+ mOverlayManager.commit(new OverlayManagerTransaction.Builder()
+ .setEnabled(overlay.getIdentifier(), true, mUserId)
+ .build());
+
+ info = mOverlayManager.getOverlayInfo(overlay.getIdentifier(), mUserHandle);
+ assertNotNull(info);
+ assertThat(info.isEnabled()).isTrue();
+
+ if (!latch1.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+ fail("Fail to wait configuration changes for build and enabling frro, "
+ + "onConfigurationChanged() has not been invoked.");
+ }
+
+ final CountDownLatch latch2 = new CountDownLatch(1);
+ mActivity.setConfigurationChangedCallback(() -> {
+ Resources r = mActivity.getApplicationContext().getResources();
+ assertThat(r.getInteger(R.integer.test_integer)).isEqualTo(TEST_INTEGER);
+ assertThat(r.getString(R.string.test_string)).isEqualTo(TEST_STRING);
+ latch2.countDown();
+ });
+
+ // unregister FRRO
+ mOverlayManager.commit(new OverlayManagerTransaction.Builder()
+ .unregisterFabricatedOverlay(overlay.getIdentifier())
+ .build());
+
+ if (!latch2.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+ fail("Fail to wait configuration changes after unregister frro,"
+ + " onConfigurationChanged() has not been invoked.");
+ }
+ }
+}
diff --git a/core/tests/resourceflaggingtests/OWNERS b/core/tests/resourceflaggingtests/OWNERS
new file mode 100644
index 000000000000..10950a193b25
--- /dev/null
+++ b/core/tests/resourceflaggingtests/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/app/RESOURCES_OWNERS
diff --git a/data/etc/OWNERS b/data/etc/OWNERS
index 701d145fe805..85dae631cac3 100644
--- a/data/etc/OWNERS
+++ b/data/etc/OWNERS
@@ -1,6 +1,5 @@
include /PACKAGE_MANAGER_OWNERS
-alanstokes@google.com
cbrubaker@google.com
hackbod@android.com
hackbod@google.com
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java
index 9ea2943bc6da..1eb95c1efb08 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java
@@ -70,10 +70,6 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer {
@NonNull
private final TaskFragmentCallback mCallback;
- @VisibleForTesting
- @Nullable
- TaskFragmentAnimationController mAnimationController;
-
/**
* Callback that notifies the controller about changes to task fragments.
*/
@@ -91,25 +87,6 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer {
mCallback = callback;
}
- @Override
- public void unregisterOrganizer() {
- if (mAnimationController != null) {
- mAnimationController.unregisterRemoteAnimations();
- mAnimationController = null;
- }
- super.unregisterOrganizer();
- }
-
- /**
- * Overrides the animation for transitions of embedded activities organized by this organizer.
- */
- void overrideSplitAnimation() {
- if (mAnimationController == null) {
- mAnimationController = new TaskFragmentAnimationController(this);
- }
- mAnimationController.registerRemoteAnimations();
- }
-
/**
* Starts a new Activity and puts it into split with an existing Activity side-by-side.
* @param launchingFragmentToken token for the launching TaskFragment. If it exists, it will
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 7ddda1f98809..b12072373c5d 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -114,7 +114,6 @@ import java.util.function.BiConsumer;
public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmentCallback,
ActivityEmbeddingComponent, DividerPresenter.DragEventCallback {
static final String TAG = "SplitController";
- static final boolean ENABLE_SHELL_TRANSITIONS = true;
// TODO(b/243518738): Move to WM Extensions if we have requirement of overlay without
// association. It's not set in WM Extensions nor Wm Jetpack library currently.
@@ -205,11 +204,9 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
/** Listener registered to {@link ClientTransactionListenerController}. */
@GuardedBy("mLock")
- @Nullable
+ @NonNull
private final BiConsumer<IBinder, ActivityWindowInfo> mActivityWindowInfoListener =
- Flags.activityWindowInfoFlag()
- ? this::onActivityWindowInfoChanged
- : null;
+ this::onActivityWindowInfoChanged;
private final Handler mHandler;
private final MainThreadExecutor mExecutor;
@@ -3097,20 +3094,14 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
public boolean isActivityEmbedded(@NonNull Activity activity) {
Objects.requireNonNull(activity);
synchronized (mLock) {
- if (Flags.activityWindowInfoFlag()) {
- final ActivityWindowInfo activityWindowInfo = getActivityWindowInfo(activity);
- return activityWindowInfo != null && activityWindowInfo.isEmbedded();
- }
- return mPresenter.isActivityEmbedded(activity.getActivityToken());
+ final ActivityWindowInfo activityWindowInfo = getActivityWindowInfo(activity);
+ return activityWindowInfo != null && activityWindowInfo.isEmbedded();
}
}
@Override
public void setEmbeddedActivityWindowInfoCallback(@NonNull Executor executor,
@NonNull Consumer<EmbeddedActivityWindowInfo> callback) {
- if (!Flags.activityWindowInfoFlag()) {
- return;
- }
Objects.requireNonNull(executor);
Objects.requireNonNull(callback);
synchronized (mLock) {
@@ -3124,9 +3115,6 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
@Override
public void clearEmbeddedActivityWindowInfoCallback() {
- if (!Flags.activityWindowInfoFlag()) {
- return;
- }
synchronized (mLock) {
if (mEmbeddedActivityWindowInfoCallback == null) {
return;
@@ -3147,9 +3135,6 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
@Nullable
@Override
public EmbeddedActivityWindowInfo getEmbeddedActivityWindowInfo(@NonNull Activity activity) {
- if (!Flags.activityWindowInfoFlag()) {
- return null;
- }
synchronized (mLock) {
final ActivityWindowInfo activityWindowInfo = getActivityWindowInfo(activity);
return activityWindowInfo != null
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
index eb1fc23d6b00..ea60b1531a3f 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
@@ -166,11 +166,6 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
mWindowLayoutComponent = windowLayoutComponent;
mController = controller;
registerOrganizer();
- if (!SplitController.ENABLE_SHELL_TRANSITIONS) {
- // TODO(b/207070762): cleanup with legacy app transition
- // Animation will be handled by WM Shell when Shell transition is enabled.
- overrideSplitAnimation();
- }
}
/**
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationAdapter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationAdapter.java
deleted file mode 100644
index 33220c44a3b5..000000000000
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationAdapter.java
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.window.extensions.embedding;
-
-import static android.graphics.Matrix.MTRANS_X;
-import static android.graphics.Matrix.MTRANS_Y;
-import static android.view.RemoteAnimationTarget.MODE_CLOSING;
-
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.view.Choreographer;
-import android.view.RemoteAnimationTarget;
-import android.view.SurfaceControl;
-import android.view.animation.Animation;
-import android.view.animation.Transformation;
-
-import androidx.annotation.NonNull;
-
-/**
- * Wrapper to handle the TaskFragment animation update in one {@link SurfaceControl.Transaction}.
- *
- * The base adapter can be used for {@link RemoteAnimationTarget} that is simple open/close.
- */
-class TaskFragmentAnimationAdapter {
-
- /**
- * If {@link #mOverrideLayer} is set to this value, we don't want to override the surface layer.
- */
- private static final int LAYER_NO_OVERRIDE = -1;
-
- @NonNull
- final Animation mAnimation;
- @NonNull
- final RemoteAnimationTarget mTarget;
- @NonNull
- final SurfaceControl mLeash;
- /** Area in absolute coordinate that the animation surface shouldn't go beyond. */
- @NonNull
- private final Rect mWholeAnimationBounds = new Rect();
- /**
- * Area in absolute coordinate that should represent all the content to show for this window.
- * This should be the end bounds for opening window, and start bounds for closing window in case
- * the window is resizing during the open/close transition.
- */
- @NonNull
- private final Rect mContentBounds = new Rect();
- /** Offset relative to the window parent surface for {@link #mContentBounds}. */
- @NonNull
- private final Point mContentRelOffset = new Point();
-
- @NonNull
- final Transformation mTransformation = new Transformation();
- @NonNull
- final float[] mMatrix = new float[9];
- @NonNull
- final float[] mVecs = new float[4];
- @NonNull
- final Rect mRect = new Rect();
- private boolean mIsFirstFrame = true;
- private int mOverrideLayer = LAYER_NO_OVERRIDE;
-
- TaskFragmentAnimationAdapter(@NonNull Animation animation,
- @NonNull RemoteAnimationTarget target) {
- this(animation, target, target.leash, target.screenSpaceBounds);
- }
-
- /**
- * @param leash the surface to animate.
- * @param wholeAnimationBounds area in absolute coordinate that the animation surface shouldn't
- * go beyond.
- */
- TaskFragmentAnimationAdapter(@NonNull Animation animation,
- @NonNull RemoteAnimationTarget target, @NonNull SurfaceControl leash,
- @NonNull Rect wholeAnimationBounds) {
- mAnimation = animation;
- mTarget = target;
- mLeash = leash;
- mWholeAnimationBounds.set(wholeAnimationBounds);
- if (target.mode == MODE_CLOSING) {
- // When it is closing, we want to show the content at the start position in case the
- // window is resizing as well. For example, when the activities is changing from split
- // to stack, the bottom TaskFragment will be resized to fullscreen when hiding.
- final Rect startBounds = target.startBounds;
- final Rect endBounds = target.screenSpaceBounds;
- mContentBounds.set(startBounds);
- mContentRelOffset.set(target.localBounds.left, target.localBounds.top);
- mContentRelOffset.offset(
- startBounds.left - endBounds.left,
- startBounds.top - endBounds.top);
- } else {
- mContentBounds.set(target.screenSpaceBounds);
- mContentRelOffset.set(target.localBounds.left, target.localBounds.top);
- }
- }
-
- /**
- * Surface layer to be set at the first frame of the animation. We will not set the layer if it
- * is set to {@link #LAYER_NO_OVERRIDE}.
- */
- final void overrideLayer(int layer) {
- mOverrideLayer = layer;
- }
-
- /** Called on frame update. */
- final void onAnimationUpdate(@NonNull SurfaceControl.Transaction t, long currentPlayTime) {
- if (mIsFirstFrame) {
- t.show(mLeash);
- if (mOverrideLayer != LAYER_NO_OVERRIDE) {
- t.setLayer(mLeash, mOverrideLayer);
- }
- mIsFirstFrame = false;
- }
-
- // Extract the transformation to the current time.
- mAnimation.getTransformation(Math.min(currentPlayTime, mAnimation.getDuration()),
- mTransformation);
- t.setFrameTimelineVsync(Choreographer.getInstance().getVsyncId());
- onAnimationUpdateInner(t);
- }
-
- /** To be overridden by subclasses to adjust the animation surface change. */
- void onAnimationUpdateInner(@NonNull SurfaceControl.Transaction t) {
- // Update the surface position and alpha.
- mTransformation.getMatrix().postTranslate(mContentRelOffset.x, mContentRelOffset.y);
- t.setMatrix(mLeash, mTransformation.getMatrix(), mMatrix);
- t.setAlpha(mLeash, mTransformation.getAlpha());
-
- // Get current surface bounds in absolute coordinate.
- // positionX/Y are in local coordinate, so minus the local offset to get the slide amount.
- final int positionX = Math.round(mMatrix[MTRANS_X]);
- final int positionY = Math.round(mMatrix[MTRANS_Y]);
- final Rect cropRect = new Rect(mContentBounds);
- cropRect.offset(positionX - mContentRelOffset.x, positionY - mContentRelOffset.y);
-
- // Store the current offset of the surface top left from (0,0) in absolute coordinate.
- final int offsetX = cropRect.left;
- final int offsetY = cropRect.top;
-
- // Intersect to make sure the animation happens within the whole animation bounds.
- if (!cropRect.intersect(mWholeAnimationBounds)) {
- // Hide the surface when it is outside of the animation area.
- t.setAlpha(mLeash, 0);
- }
-
- // cropRect is in absolute coordinate, so we need to translate it to surface top left.
- cropRect.offset(-offsetX, -offsetY);
- t.setCrop(mLeash, cropRect);
- }
-
- /** Called after animation finished. */
- final void onAnimationEnd(@NonNull SurfaceControl.Transaction t) {
- onAnimationUpdate(t, mAnimation.getDuration());
- }
-
- final long getDurationHint() {
- return mAnimation.computeDurationHint();
- }
-
- /**
- * Should be used for the animation of the snapshot of a {@link RemoteAnimationTarget} that has
- * size change.
- */
- static class SnapshotAdapter extends TaskFragmentAnimationAdapter {
-
- SnapshotAdapter(@NonNull Animation animation, @NonNull RemoteAnimationTarget target) {
- // Start leash is the snapshot of the starting surface.
- super(animation, target, target.startLeash, target.screenSpaceBounds);
- }
-
- @Override
- void onAnimationUpdateInner(@NonNull SurfaceControl.Transaction t) {
- // Snapshot should always be placed at the top left of the animation leash.
- mTransformation.getMatrix().postTranslate(0, 0);
- t.setMatrix(mLeash, mTransformation.getMatrix(), mMatrix);
- t.setAlpha(mLeash, mTransformation.getAlpha());
- }
- }
-
- /**
- * Should be used for the animation of the {@link RemoteAnimationTarget} that has size change.
- */
- static class BoundsChangeAdapter extends TaskFragmentAnimationAdapter {
-
- BoundsChangeAdapter(@NonNull Animation animation, @NonNull RemoteAnimationTarget target) {
- super(animation, target);
- }
-
- @Override
- void onAnimationUpdateInner(@NonNull SurfaceControl.Transaction t) {
- mTransformation.getMatrix().postTranslate(
- mTarget.localBounds.left, mTarget.localBounds.top);
- t.setMatrix(mLeash, mTransformation.getMatrix(), mMatrix);
- t.setAlpha(mLeash, mTransformation.getAlpha());
-
- // The following applies an inverse scale to the clip-rect so that it crops "after" the
- // scale instead of before.
- mVecs[1] = mVecs[2] = 0;
- mVecs[0] = mVecs[3] = 1;
- mTransformation.getMatrix().mapVectors(mVecs);
- mVecs[0] = 1.f / mVecs[0];
- mVecs[3] = 1.f / mVecs[3];
- final Rect clipRect = mTransformation.getClipRect();
- mRect.left = (int) (clipRect.left * mVecs[0] + 0.5f);
- mRect.right = (int) (clipRect.right * mVecs[0] + 0.5f);
- mRect.top = (int) (clipRect.top * mVecs[3] + 0.5f);
- mRect.bottom = (int) (clipRect.bottom * mVecs[3] + 0.5f);
- t.setWindowCrop(mLeash, mRect);
- }
- }
-}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationController.java
deleted file mode 100644
index d7eb9a01f57c..000000000000
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationController.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.window.extensions.embedding;
-
-import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_CLOSE;
-import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_OPEN;
-import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CHANGE;
-import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CLOSE;
-import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_OPEN;
-
-import android.util.Log;
-import android.view.RemoteAnimationAdapter;
-import android.view.RemoteAnimationDefinition;
-import android.window.TaskFragmentOrganizer;
-
-import androidx.annotation.NonNull;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-/** Controls the TaskFragment remote animations. */
-class TaskFragmentAnimationController {
-
- private static final String TAG = "TaskFragAnimationCtrl";
- static final boolean DEBUG = false;
-
- private final TaskFragmentOrganizer mOrganizer;
- private final TaskFragmentAnimationRunner mRemoteRunner = new TaskFragmentAnimationRunner();
- @VisibleForTesting
- final RemoteAnimationDefinition mDefinition;
- private boolean mIsRegistered;
-
- TaskFragmentAnimationController(@NonNull TaskFragmentOrganizer organizer) {
- mOrganizer = organizer;
- mDefinition = new RemoteAnimationDefinition();
- final RemoteAnimationAdapter animationAdapter =
- new RemoteAnimationAdapter(mRemoteRunner, 0, 0, true /* changeNeedsSnapshot */);
- mDefinition.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_OPEN, animationAdapter);
- mDefinition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_OPEN, animationAdapter);
- mDefinition.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_CLOSE, animationAdapter);
- mDefinition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_CLOSE, animationAdapter);
- mDefinition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_CHANGE, animationAdapter);
- }
-
- void registerRemoteAnimations() {
- if (DEBUG) {
- Log.v(TAG, "registerRemoteAnimations");
- }
- if (mIsRegistered) {
- return;
- }
- mOrganizer.registerRemoteAnimations(mDefinition);
- mIsRegistered = true;
- }
-
- void unregisterRemoteAnimations() {
- if (DEBUG) {
- Log.v(TAG, "unregisterRemoteAnimations");
- }
- if (!mIsRegistered) {
- return;
- }
- mOrganizer.unregisterRemoteAnimations();
- mIsRegistered = false;
- }
-}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java
deleted file mode 100644
index d9b73a8290f5..000000000000
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java
+++ /dev/null
@@ -1,309 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.window.extensions.embedding;
-
-import static android.os.Process.THREAD_PRIORITY_DISPLAY;
-import static android.view.RemoteAnimationTarget.MODE_CHANGING;
-import static android.view.RemoteAnimationTarget.MODE_CLOSING;
-import static android.view.RemoteAnimationTarget.MODE_OPENING;
-import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_CLOSE;
-import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_OPEN;
-import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CHANGE;
-import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CLOSE;
-import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_OPEN;
-import static android.view.WindowManagerPolicyConstants.TYPE_LAYER_OFFSET;
-
-import android.animation.Animator;
-import android.animation.ValueAnimator;
-import android.graphics.Rect;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.RemoteException;
-import android.util.Log;
-import android.view.IRemoteAnimationFinishedCallback;
-import android.view.IRemoteAnimationRunner;
-import android.view.RemoteAnimationTarget;
-import android.view.SurfaceControl;
-import android.view.WindowManager;
-import android.view.animation.Animation;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.function.BiFunction;
-
-/** To run the TaskFragment animations. */
-class TaskFragmentAnimationRunner extends IRemoteAnimationRunner.Stub {
-
- private static final String TAG = "TaskFragAnimationRunner";
- private final Handler mHandler;
- private final TaskFragmentAnimationSpec mAnimationSpec;
-
- TaskFragmentAnimationRunner() {
- HandlerThread animationThread = new HandlerThread(
- "androidx.window.extensions.embedding", THREAD_PRIORITY_DISPLAY);
- animationThread.start();
- mHandler = animationThread.getThreadHandler();
- mAnimationSpec = new TaskFragmentAnimationSpec(mHandler);
- }
-
- @Nullable
- private Animator mAnimator;
-
- @Override
- public void onAnimationStart(@WindowManager.TransitionOldType int transit,
- @NonNull RemoteAnimationTarget[] apps,
- @NonNull RemoteAnimationTarget[] wallpapers,
- @NonNull RemoteAnimationTarget[] nonApps,
- @NonNull IRemoteAnimationFinishedCallback finishedCallback) {
- if (wallpapers.length != 0 || nonApps.length != 0) {
- throw new IllegalArgumentException("TaskFragment shouldn't handle animation with"
- + "wallpaper or non-app windows.");
- }
- if (TaskFragmentAnimationController.DEBUG) {
- Log.v(TAG, "onAnimationStart transit=" + transit);
- }
- mHandler.post(() -> startAnimation(transit, apps, finishedCallback));
- }
-
- @Override
- public void onAnimationCancelled() {
- mHandler.post(this::cancelAnimation);
- }
-
- /** Creates and starts animation. */
- private void startAnimation(@WindowManager.TransitionOldType int transit,
- @NonNull RemoteAnimationTarget[] targets,
- @NonNull IRemoteAnimationFinishedCallback finishedCallback) {
- if (mAnimator != null) {
- Log.w(TAG, "start new animation when the previous one is not finished yet.");
- mAnimator.cancel();
- }
- mAnimator = createAnimator(transit, targets, finishedCallback);
- mAnimator.start();
- }
-
- /** Cancels animation. */
- private void cancelAnimation() {
- if (mAnimator == null) {
- return;
- }
- mAnimator.cancel();
- mAnimator = null;
- }
-
- /** Creates the animator given the transition type and windows. */
- @NonNull
- private Animator createAnimator(@WindowManager.TransitionOldType int transit,
- @NonNull RemoteAnimationTarget[] targets,
- @NonNull IRemoteAnimationFinishedCallback finishedCallback) {
- final List<TaskFragmentAnimationAdapter> adapters =
- createAnimationAdapters(transit, targets);
- long duration = 0;
- for (TaskFragmentAnimationAdapter adapter : adapters) {
- duration = Math.max(duration, adapter.getDurationHint());
- }
- final ValueAnimator animator = ValueAnimator.ofFloat(0, 1);
- animator.setDuration(duration);
- animator.addUpdateListener((anim) -> {
- // Update all adapters in the same transaction.
- final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
- for (TaskFragmentAnimationAdapter adapter : adapters) {
- adapter.onAnimationUpdate(t, animator.getCurrentPlayTime());
- }
- t.apply();
- });
- animator.addListener(new Animator.AnimatorListener() {
- @Override
- public void onAnimationStart(Animator animation) {}
-
- @Override
- public void onAnimationEnd(Animator animation) {
- final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
- for (TaskFragmentAnimationAdapter adapter : adapters) {
- adapter.onAnimationEnd(t);
- }
- t.apply();
-
- try {
- finishedCallback.onAnimationFinished();
- } catch (RemoteException e) {
- e.rethrowFromSystemServer();
- }
- mAnimator = null;
- }
-
- @Override
- public void onAnimationCancel(Animator animation) {}
-
- @Override
- public void onAnimationRepeat(Animator animation) {}
- });
- return animator;
- }
-
- /** List of {@link TaskFragmentAnimationAdapter} to handle animations on all window targets. */
- @NonNull
- private List<TaskFragmentAnimationAdapter> createAnimationAdapters(
- @WindowManager.TransitionOldType int transit,
- @NonNull RemoteAnimationTarget[] targets) {
- switch (transit) {
- case TRANSIT_OLD_ACTIVITY_OPEN:
- case TRANSIT_OLD_TASK_FRAGMENT_OPEN:
- return createOpenAnimationAdapters(targets);
- case TRANSIT_OLD_ACTIVITY_CLOSE:
- case TRANSIT_OLD_TASK_FRAGMENT_CLOSE:
- return createCloseAnimationAdapters(targets);
- case TRANSIT_OLD_TASK_FRAGMENT_CHANGE:
- return createChangeAnimationAdapters(targets);
- default:
- throw new IllegalArgumentException("Unhandled transit type=" + transit);
- }
- }
-
- @NonNull
- private List<TaskFragmentAnimationAdapter> createOpenAnimationAdapters(
- @NonNull RemoteAnimationTarget[] targets) {
- return createOpenCloseAnimationAdapters(targets, true /* isOpening */,
- mAnimationSpec::loadOpenAnimation);
- }
-
- @NonNull
- private List<TaskFragmentAnimationAdapter> createCloseAnimationAdapters(
- @NonNull RemoteAnimationTarget[] targets) {
- return createOpenCloseAnimationAdapters(targets, false /* isOpening */,
- mAnimationSpec::loadCloseAnimation);
- }
-
- /**
- * Creates {@link TaskFragmentAnimationAdapter} for OPEN and CLOSE types of transition.
- * @param isOpening {@code true} for OPEN type, {@code false} for CLOSE type.
- */
- @NonNull
- private List<TaskFragmentAnimationAdapter> createOpenCloseAnimationAdapters(
- @NonNull RemoteAnimationTarget[] targets, boolean isOpening,
- @NonNull BiFunction<RemoteAnimationTarget, Rect, Animation> animationProvider) {
- // We need to know if the target window is only a partial of the whole animation screen.
- // If so, we will need to adjust it to make the whole animation screen looks like one.
- final List<RemoteAnimationTarget> openingTargets = new ArrayList<>();
- final List<RemoteAnimationTarget> closingTargets = new ArrayList<>();
- final Rect openingWholeScreenBounds = new Rect();
- final Rect closingWholeScreenBounds = new Rect();
- for (RemoteAnimationTarget target : targets) {
- if (target.mode != MODE_CLOSING) {
- openingTargets.add(target);
- openingWholeScreenBounds.union(target.screenSpaceBounds);
- } else {
- closingTargets.add(target);
- closingWholeScreenBounds.union(target.screenSpaceBounds);
- // Union the start bounds since this may be the ClosingChanging animation.
- closingWholeScreenBounds.union(target.startBounds);
- }
- }
-
- // For OPEN transition, open windows should be above close windows.
- // For CLOSE transition, open windows should be below close windows.
- int offsetLayer = TYPE_LAYER_OFFSET;
- final List<TaskFragmentAnimationAdapter> adapters = new ArrayList<>();
- for (RemoteAnimationTarget target : openingTargets) {
- final TaskFragmentAnimationAdapter adapter = createOpenCloseAnimationAdapter(target,
- animationProvider, openingWholeScreenBounds);
- if (isOpening) {
- adapter.overrideLayer(offsetLayer++);
- }
- adapters.add(adapter);
- }
- for (RemoteAnimationTarget target : closingTargets) {
- final TaskFragmentAnimationAdapter adapter = createOpenCloseAnimationAdapter(target,
- animationProvider, closingWholeScreenBounds);
- if (!isOpening) {
- adapter.overrideLayer(offsetLayer++);
- }
- adapters.add(adapter);
- }
- return adapters;
- }
-
- @NonNull
- private TaskFragmentAnimationAdapter createOpenCloseAnimationAdapter(
- @NonNull RemoteAnimationTarget target,
- @NonNull BiFunction<RemoteAnimationTarget, Rect, Animation> animationProvider,
- @NonNull Rect wholeAnimationBounds) {
- final Animation animation = animationProvider.apply(target, wholeAnimationBounds);
- return new TaskFragmentAnimationAdapter(animation, target, target.leash,
- wholeAnimationBounds);
- }
-
- @NonNull
- private List<TaskFragmentAnimationAdapter> createChangeAnimationAdapters(
- @NonNull RemoteAnimationTarget[] targets) {
- if (shouldUseJumpCutForChangeAnimation(targets)) {
- return new ArrayList<>();
- }
-
- final List<TaskFragmentAnimationAdapter> adapters = new ArrayList<>();
- for (RemoteAnimationTarget target : targets) {
- if (target.mode == MODE_CHANGING) {
- // This is the target with bounds change.
- final Animation[] animations =
- mAnimationSpec.createChangeBoundsChangeAnimations(target);
- // Adapter for the starting snapshot leash.
- adapters.add(new TaskFragmentAnimationAdapter.SnapshotAdapter(
- animations[0], target));
- // Adapter for the ending bounds changed leash.
- adapters.add(new TaskFragmentAnimationAdapter.BoundsChangeAdapter(
- animations[1], target));
- continue;
- }
-
- // These are the other targets that don't have bounds change in the same transition.
- final Animation animation;
- if (target.hasAnimatingParent) {
- // No-op if it will be covered by the changing parent window.
- animation = TaskFragmentAnimationSpec.createNoopAnimation(target);
- } else if (target.mode == MODE_CLOSING) {
- animation = mAnimationSpec.createChangeBoundsCloseAnimation(target);
- } else {
- animation = mAnimationSpec.createChangeBoundsOpenAnimation(target);
- }
- adapters.add(new TaskFragmentAnimationAdapter(animation, target));
- }
- return adapters;
- }
-
- /**
- * Whether we should use jump cut for the change transition.
- * This normally happens when opening a new secondary with the existing primary using a
- * different split layout. This can be complicated, like from horizontal to vertical split with
- * new split pairs.
- * Uses a jump cut animation to simplify.
- */
- private boolean shouldUseJumpCutForChangeAnimation(@NonNull RemoteAnimationTarget[] targets) {
- boolean hasOpeningWindow = false;
- boolean hasClosingWindow = false;
- for (RemoteAnimationTarget target : targets) {
- if (target.hasAnimatingParent) {
- continue;
- }
- hasOpeningWindow |= target.mode == MODE_OPENING;
- hasClosingWindow |= target.mode == MODE_CLOSING;
- }
- return hasOpeningWindow && hasClosingWindow;
- }
-}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationSpec.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationSpec.java
deleted file mode 100644
index 1f866c3b99c9..000000000000
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationSpec.java
+++ /dev/null
@@ -1,267 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.window.extensions.embedding;
-
-import static android.view.RemoteAnimationTarget.MODE_CLOSING;
-
-import android.app.ActivityThread;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.database.ContentObserver;
-import android.graphics.Rect;
-import android.os.Handler;
-import android.provider.Settings;
-import android.view.RemoteAnimationTarget;
-import android.view.WindowManager;
-import android.view.animation.AlphaAnimation;
-import android.view.animation.Animation;
-import android.view.animation.AnimationSet;
-import android.view.animation.AnimationUtils;
-import android.view.animation.ClipRectAnimation;
-import android.view.animation.Interpolator;
-import android.view.animation.LinearInterpolator;
-import android.view.animation.ScaleAnimation;
-import android.view.animation.TranslateAnimation;
-
-import androidx.annotation.NonNull;
-
-import com.android.internal.R;
-import com.android.internal.policy.AttributeCache;
-import com.android.internal.policy.TransitionAnimation;
-
-/** Animation spec for TaskFragment transition. */
-// TODO(b/206557124): provide an easier way to customize animation
-class TaskFragmentAnimationSpec {
-
- private static final String TAG = "TaskFragAnimationSpec";
- private static final int CHANGE_ANIMATION_DURATION = 517;
- private static final int CHANGE_ANIMATION_FADE_DURATION = 80;
- private static final int CHANGE_ANIMATION_FADE_OFFSET = 30;
-
- private final Context mContext;
- private final TransitionAnimation mTransitionAnimation;
- private final Interpolator mFastOutExtraSlowInInterpolator;
- private final LinearInterpolator mLinearInterpolator;
- private float mTransitionAnimationScaleSetting;
-
- TaskFragmentAnimationSpec(@NonNull Handler handler) {
- mContext = ActivityThread.currentActivityThread().getApplication();
- mTransitionAnimation = new TransitionAnimation(mContext, false /* debug */, TAG);
- // Initialize the AttributeCache for the TransitionAnimation.
- AttributeCache.init(mContext);
- mFastOutExtraSlowInInterpolator = AnimationUtils.loadInterpolator(
- mContext, android.R.interpolator.fast_out_extra_slow_in);
- mLinearInterpolator = new LinearInterpolator();
-
- // The transition animation should be adjusted based on the developer option.
- final ContentResolver resolver = mContext.getContentResolver();
- mTransitionAnimationScaleSetting = getTransitionAnimationScaleSetting();
- resolver.registerContentObserver(
- Settings.Global.getUriFor(Settings.Global.TRANSITION_ANIMATION_SCALE), false,
- new SettingsObserver(handler));
- }
-
- /** For target that doesn't need to be animated. */
- @NonNull
- static Animation createNoopAnimation(@NonNull RemoteAnimationTarget target) {
- // Noop but just keep the target showing/hiding.
- final float alpha = target.mode == MODE_CLOSING ? 0f : 1f;
- return new AlphaAnimation(alpha, alpha);
- }
-
- /** Animation for target that is opening in a change transition. */
- @NonNull
- Animation createChangeBoundsOpenAnimation(@NonNull RemoteAnimationTarget target) {
- final Rect parentBounds = target.taskInfo.configuration.windowConfiguration.getBounds();
- final Rect bounds = target.screenSpaceBounds;
- final int startLeft;
- final int startTop;
- if (parentBounds.top == bounds.top && parentBounds.bottom == bounds.bottom) {
- // The window will be animated in from left or right depending on its position.
- startTop = 0;
- startLeft = parentBounds.left == bounds.left ? -bounds.width() : bounds.width();
- } else {
- // The window will be animated in from top or bottom depending on its position.
- startTop = parentBounds.top == bounds.top ? -bounds.height() : bounds.height();
- startLeft = 0;
- }
-
- // The position should be 0-based as we will post translate in
- // TaskFragmentAnimationAdapter#onAnimationUpdate
- final Animation animation = new TranslateAnimation(startLeft, 0, startTop, 0);
- animation.setInterpolator(mFastOutExtraSlowInInterpolator);
- animation.setDuration(CHANGE_ANIMATION_DURATION);
- animation.initialize(bounds.width(), bounds.height(), bounds.width(), bounds.height());
- animation.scaleCurrentDuration(mTransitionAnimationScaleSetting);
- return animation;
- }
-
- /** Animation for target that is closing in a change transition. */
- @NonNull
- Animation createChangeBoundsCloseAnimation(@NonNull RemoteAnimationTarget target) {
- final Rect parentBounds = target.taskInfo.configuration.windowConfiguration.getBounds();
- // Use startBounds if the window is closing in case it may also resize.
- final Rect bounds = target.startBounds;
- final int endTop;
- final int endLeft;
- if (parentBounds.top == bounds.top && parentBounds.bottom == bounds.bottom) {
- // The window will be animated out to left or right depending on its position.
- endTop = 0;
- endLeft = parentBounds.left == bounds.left ? -bounds.width() : bounds.width();
- } else {
- // The window will be animated out to top or bottom depending on its position.
- endTop = parentBounds.top == bounds.top ? -bounds.height() : bounds.height();
- endLeft = 0;
- }
-
- // The position should be 0-based as we will post translate in
- // TaskFragmentAnimationAdapter#onAnimationUpdate
- final Animation animation = new TranslateAnimation(0, endLeft, 0, endTop);
- animation.setInterpolator(mFastOutExtraSlowInInterpolator);
- animation.setDuration(CHANGE_ANIMATION_DURATION);
- animation.initialize(bounds.width(), bounds.height(), bounds.width(), bounds.height());
- animation.scaleCurrentDuration(mTransitionAnimationScaleSetting);
- return animation;
- }
-
- /**
- * Animation for target that is changing (bounds change) in a change transition.
- * @return the return array always has two elements. The first one is for the start leash, and
- * the second one is for the end leash.
- */
- @NonNull
- Animation[] createChangeBoundsChangeAnimations(@NonNull RemoteAnimationTarget target) {
- // Both start bounds and end bounds are in screen coordinates. We will post translate
- // to the local coordinates in TaskFragmentAnimationAdapter#onAnimationUpdate
- final Rect startBounds = target.startBounds;
- final Rect parentBounds = target.taskInfo.configuration.windowConfiguration.getBounds();
- final Rect endBounds = target.screenSpaceBounds;
- float scaleX = ((float) startBounds.width()) / endBounds.width();
- float scaleY = ((float) startBounds.height()) / endBounds.height();
- // Start leash is a child of the end leash. Reverse the scale so that the start leash won't
- // be scaled up with its parent.
- float startScaleX = 1.f / scaleX;
- float startScaleY = 1.f / scaleY;
-
- // The start leash will be fade out.
- final AnimationSet startSet = new AnimationSet(false /* shareInterpolator */);
- final Animation startAlpha = new AlphaAnimation(1f, 0f);
- startAlpha.setInterpolator(mLinearInterpolator);
- startAlpha.setDuration(CHANGE_ANIMATION_FADE_DURATION);
- startAlpha.setStartOffset(CHANGE_ANIMATION_FADE_OFFSET);
- startSet.addAnimation(startAlpha);
- final Animation startScale = new ScaleAnimation(startScaleX, startScaleX, startScaleY,
- startScaleY);
- startScale.setInterpolator(mFastOutExtraSlowInInterpolator);
- startScale.setDuration(CHANGE_ANIMATION_DURATION);
- startSet.addAnimation(startScale);
- startSet.initialize(startBounds.width(), startBounds.height(), endBounds.width(),
- endBounds.height());
- startSet.scaleCurrentDuration(mTransitionAnimationScaleSetting);
-
- // The end leash will be moved into the end position while scaling.
- final AnimationSet endSet = new AnimationSet(true /* shareInterpolator */);
- endSet.setInterpolator(mFastOutExtraSlowInInterpolator);
- final Animation endScale = new ScaleAnimation(scaleX, 1, scaleY, 1);
- endScale.setDuration(CHANGE_ANIMATION_DURATION);
- endSet.addAnimation(endScale);
- // The position should be 0-based as we will post translate in
- // TaskFragmentAnimationAdapter#onAnimationUpdate
- final Animation endTranslate = new TranslateAnimation(startBounds.left - endBounds.left, 0,
- startBounds.top - endBounds.top, 0);
- endTranslate.setDuration(CHANGE_ANIMATION_DURATION);
- endSet.addAnimation(endTranslate);
- // The end leash is resizing, we should update the window crop based on the clip rect.
- final Rect startClip = new Rect(startBounds);
- final Rect endClip = new Rect(endBounds);
- startClip.offsetTo(0, 0);
- endClip.offsetTo(0, 0);
- final Animation clipAnim = new ClipRectAnimation(startClip, endClip);
- clipAnim.setDuration(CHANGE_ANIMATION_DURATION);
- endSet.addAnimation(clipAnim);
- endSet.initialize(startBounds.width(), startBounds.height(), parentBounds.width(),
- parentBounds.height());
- endSet.scaleCurrentDuration(mTransitionAnimationScaleSetting);
-
- return new Animation[]{startSet, endSet};
- }
-
- @NonNull
- Animation loadOpenAnimation(@NonNull RemoteAnimationTarget target,
- @NonNull Rect wholeAnimationBounds) {
- final boolean isEnter = target.mode != MODE_CLOSING;
- final Animation animation;
- // Background color on TaskDisplayArea has already been set earlier in
- // WindowContainer#getAnimationAdapter.
- if (target.showBackdrop) {
- animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter
- ? com.android.internal.R.anim.task_fragment_clear_top_open_enter
- : com.android.internal.R.anim.task_fragment_clear_top_open_exit);
- } else {
- animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter
- ? com.android.internal.R.anim.task_fragment_open_enter
- : com.android.internal.R.anim.task_fragment_open_exit);
- }
- // Use the whole animation bounds instead of the change bounds, so that when multiple change
- // targets are opening at the same time, the animation applied to each will be the same.
- // Otherwise, we may see gap between the activities that are launching together.
- animation.initialize(wholeAnimationBounds.width(), wholeAnimationBounds.height(),
- wholeAnimationBounds.width(), wholeAnimationBounds.height());
- animation.scaleCurrentDuration(mTransitionAnimationScaleSetting);
- return animation;
- }
-
- @NonNull
- Animation loadCloseAnimation(@NonNull RemoteAnimationTarget target,
- @NonNull Rect wholeAnimationBounds) {
- final boolean isEnter = target.mode != MODE_CLOSING;
- final Animation animation;
- if (target.showBackdrop) {
- animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter
- ? com.android.internal.R.anim.task_fragment_clear_top_close_enter
- : com.android.internal.R.anim.task_fragment_clear_top_close_exit);
- } else {
- animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter
- ? com.android.internal.R.anim.task_fragment_close_enter
- : com.android.internal.R.anim.task_fragment_close_exit);
- }
- // Use the whole animation bounds instead of the change bounds, so that when multiple change
- // targets are closing at the same time, the animation applied to each will be the same.
- // Otherwise, we may see gap between the activities that are finishing together.
- animation.initialize(wholeAnimationBounds.width(), wholeAnimationBounds.height(),
- wholeAnimationBounds.width(), wholeAnimationBounds.height());
- animation.scaleCurrentDuration(mTransitionAnimationScaleSetting);
- return animation;
- }
-
- private float getTransitionAnimationScaleSetting() {
- return WindowManager.fixScale(Settings.Global.getFloat(mContext.getContentResolver(),
- Settings.Global.TRANSITION_ANIMATION_SCALE, mContext.getResources().getFloat(
- R.dimen.config_appTransitionAnimationDurationScaleDefault)));
- }
-
- private class SettingsObserver extends ContentObserver {
- SettingsObserver(@NonNull Handler handler) {
- super(handler);
- }
-
- @Override
- public void onChange(boolean selfChange) {
- mTransitionAnimationScaleSetting = getTransitionAnimationScaleSetting();
- }
- }
-}
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java
index 7b473b04548c..ad41b18dcbc6 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java
@@ -23,8 +23,6 @@ import static androidx.window.extensions.embedding.EmbeddingTestUtils.createTest
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
@@ -86,24 +84,6 @@ public class JetpackTaskFragmentOrganizerTest {
}
@Test
- public void testUnregisterOrganizer() {
- mOrganizer.overrideSplitAnimation();
- mOrganizer.unregisterOrganizer();
-
- verify(mOrganizer).unregisterRemoteAnimations();
- }
-
- @Test
- public void testOverrideSplitAnimation() {
- assertNull(mOrganizer.mAnimationController);
-
- mOrganizer.overrideSplitAnimation();
-
- assertNotNull(mOrganizer.mAnimationController);
- verify(mOrganizer).registerRemoteAnimations(mOrganizer.mAnimationController.mDefinition);
- }
-
- @Test
public void testExpandTaskFragment() {
final TaskContainer taskContainer = createTestTaskContainer();
doReturn(taskContainer).when(mSplitController).getTaskContainer(anyInt());
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 efeec82b782e..99c0ee29962c 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
@@ -103,8 +103,6 @@ import androidx.window.common.DeviceStateManagerFoldingFeatureProducer;
import androidx.window.extensions.layout.WindowLayoutComponentImpl;
import androidx.window.extensions.layout.WindowLayoutInfo;
-import com.android.window.flags.Flags;
-
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -1557,8 +1555,6 @@ public class SplitControllerTest {
@Test
public void testIsActivityEmbedded() {
- mSetFlagRule.enableFlags(Flags.FLAG_ACTIVITY_WINDOW_INFO_FLAG);
-
assertFalse(mSplitController.isActivityEmbedded(mActivity));
doReturn(true).when(mActivityWindowInfo).isEmbedded();
@@ -1568,8 +1564,6 @@ public class SplitControllerTest {
@Test
public void testGetEmbeddedActivityWindowInfo() {
- mSetFlagRule.enableFlags(Flags.FLAG_ACTIVITY_WINDOW_INFO_FLAG);
-
final boolean isEmbedded = true;
final Rect taskBounds = new Rect(0, 0, 1000, 2000);
final Rect activityStackBounds = new Rect(0, 0, 500, 2000);
@@ -1584,8 +1578,6 @@ public class SplitControllerTest {
@Test
public void testSetEmbeddedActivityWindowInfoCallback() {
- mSetFlagRule.enableFlags(Flags.FLAG_ACTIVITY_WINDOW_INFO_FLAG);
-
final ClientTransactionListenerController controller = ClientTransactionListenerController
.getInstance();
spyOn(controller);
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentAnimationControllerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentAnimationControllerTest.java
deleted file mode 100644
index a1e9f08585f6..000000000000
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentAnimationControllerTest.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.window.extensions.embedding;
-
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
-
-import static org.mockito.Mockito.never;
-
-import android.platform.test.annotations.Presubmit;
-import android.window.TaskFragmentOrganizer;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
-
-/**
- * Test class for {@link TaskFragmentAnimationController}.
- *
- * Build/Install/Run:
- * atest WMJetpackUnitTests:TaskFragmentAnimationControllerTest
- */
-@Presubmit
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class TaskFragmentAnimationControllerTest {
- @Rule
- public MockitoRule rule = MockitoJUnit.rule();
-
- @Mock
- private TaskFragmentOrganizer mOrganizer;
- private TaskFragmentAnimationController mAnimationController;
-
- @Before
- public void setup() {
- mAnimationController = new TaskFragmentAnimationController(mOrganizer);
- }
-
- @Test
- public void testRegisterRemoteAnimations() {
- mAnimationController.registerRemoteAnimations();
-
- verify(mOrganizer).registerRemoteAnimations(mAnimationController.mDefinition);
-
- mAnimationController.registerRemoteAnimations();
-
- // No extra call if it has been registered.
- verify(mOrganizer).registerRemoteAnimations(mAnimationController.mDefinition);
- }
-
- @Test
- public void testUnregisterRemoteAnimations() {
- mAnimationController.unregisterRemoteAnimations();
-
- // No call if it is not registered.
- verify(mOrganizer, never()).unregisterRemoteAnimations();
-
- mAnimationController.registerRemoteAnimations();
- mAnimationController.unregisterRemoteAnimations();
-
- verify(mOrganizer).unregisterRemoteAnimations();
-
- mAnimationController.unregisterRemoteAnimations();
-
- // No extra call if it has been unregistered.
- verify(mOrganizer).unregisterRemoteAnimations();
- }
-}
diff --git a/libs/WindowManager/Shell/Android.bp b/libs/WindowManager/Shell/Android.bp
index dbcad8aab45b..a00d003001e6 100644
--- a/libs/WindowManager/Shell/Android.bp
+++ b/libs/WindowManager/Shell/Android.bp
@@ -224,7 +224,6 @@ android_library {
"//frameworks/libs/systemui:com_android_systemui_shared_flags_lib",
"//frameworks/libs/systemui:iconloader_base",
"com_android_wm_shell_flags_lib",
- "com.android.window.flags.window-aconfig-java",
"WindowManager-Shell-proto",
"WindowManager-Shell-shared",
"perfetto_trace_java_protos",
diff --git a/libs/WindowManager/Shell/aconfig/multitasking.aconfig b/libs/WindowManager/Shell/aconfig/multitasking.aconfig
index 3ff40e0886a4..56ea7c201e53 100644
--- a/libs/WindowManager/Shell/aconfig/multitasking.aconfig
+++ b/libs/WindowManager/Shell/aconfig/multitasking.aconfig
@@ -113,16 +113,6 @@ flag {
}
flag {
- name: "animate_bubble_size_change"
- namespace: "multitasking"
- description: "Turns on the animation for bubble bar icons size change"
- bug: "335575529"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
name: "enable_taskbar_on_phones"
namespace: "multitasking"
description: "Enables taskbar on phones"
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/robolectric/phone/dark_portrait_bubbles_education.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/robolectric/phone/dark_portrait_bubbles_education.png
index 723c6b8d9c93..e02c89ae07bd 100644
--- a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/robolectric/phone/dark_portrait_bubbles_education.png
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/robolectric/phone/dark_portrait_bubbles_education.png
Binary files differ
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/robolectric/phone/light_portrait_bubbles_education.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/robolectric/phone/light_portrait_bubbles_education.png
index 723c6b8d9c93..e02c89ae07bd 100644
--- a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/robolectric/phone/light_portrait_bubbles_education.png
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/robolectric/phone/light_portrait_bubbles_education.png
Binary files differ
diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml
index 419d5c0af1a4..864f7cd421ee 100644
--- a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml
+++ b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml
@@ -19,6 +19,10 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="@dimen/desktop_mode_handle_menu_width"
android:layout_height="wrap_content"
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ android:paddingBottom="@dimen/desktop_mode_handle_menu_pill_elevation"
+ android:paddingRight="@dimen/desktop_mode_handle_menu_pill_elevation"
android:orientation="vertical">
<LinearLayout
@@ -27,7 +31,7 @@
android:layout_height="@dimen/desktop_mode_handle_menu_app_info_pill_height"
android:layout_marginTop="@dimen/desktop_mode_handle_menu_margin_top"
android:layout_marginStart="1dp"
- android:elevation="1dp"
+ android:elevation="@dimen/desktop_mode_handle_menu_pill_elevation"
android:orientation="horizontal"
android:background="@drawable/desktop_mode_decor_handle_menu_background"
android:gravity="center_vertical">
@@ -73,7 +77,7 @@
android:layout_marginTop="@dimen/desktop_mode_handle_menu_pill_spacing_margin"
android:layout_marginStart="1dp"
android:orientation="horizontal"
- android:elevation="1dp"
+ android:elevation="@dimen/desktop_mode_handle_menu_pill_elevation"
android:background="@drawable/desktop_mode_decor_handle_menu_background"
android:gravity="center_vertical">
@@ -124,7 +128,7 @@
android:layout_marginTop="@dimen/desktop_mode_handle_menu_pill_spacing_margin"
android:layout_marginStart="1dp"
android:orientation="vertical"
- android:elevation="1dp"
+ android:elevation="@dimen/desktop_mode_handle_menu_pill_elevation"
android:background="@drawable/desktop_mode_decor_handle_menu_background">
<Button
@@ -143,7 +147,7 @@
android:layout_marginTop="@dimen/desktop_mode_handle_menu_pill_spacing_margin"
android:layout_marginStart="1dp"
android:orientation="vertical"
- android:elevation="1dp"
+ android:elevation="@dimen/desktop_mode_handle_menu_pill_elevation"
android:background="@drawable/desktop_mode_decor_handle_menu_background">
<Button
diff --git a/libs/WindowManager/Shell/res/values-fa/strings.xml b/libs/WindowManager/Shell/res/values-fa/strings.xml
index 4b9be47f8023..a4711d4180bc 100644
--- a/libs/WindowManager/Shell/res/values-fa/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fa/strings.xml
@@ -96,7 +96,7 @@
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"دوربین مشکلی ندارد؟ برای بستن تک‌ضرب بزنید."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"از چندین برنامه به‌طور هم‌زمان استفاده کنید"</string>
<string name="letterbox_education_split_screen_text" msgid="449233070804658627">"برای حالت صفحهٔ دونیمه، در برنامه‌ای دیگر بکشید"</string>
- <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"برای جابه‌جا کردن برنامه، بیرون از آن دوضربه بزنید"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"برای جابه‌جا کردن برنامه، بیرون از آن دو تک‌ضرب بزنید"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"متوجه‌ام"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"برای اطلاعات بیشتر، گسترده کنید."</string>
<string name="letterbox_restart_dialog_title" msgid="8543049527871033505">"برای نمایش بهتر بازراه‌اندازی شود؟"</string>
@@ -104,7 +104,7 @@
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"لغو کردن"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"بازراه‌اندازی"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"دوباره نشان داده نشود"</string>
- <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"برای جابه‌جا کردن این برنامه\nدوضربه بزنید"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"برای جابه‌جا کردن این برنامه\nدو تک‌ضرب بزنید"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"بزرگ کردن"</string>
<string name="minimize_button_text" msgid="271592547935841753">"کوچک کردن"</string>
<string name="close_button_text" msgid="2913281996024033299">"بستن"</string>
diff --git a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
index 74d822ac02c0..7feb772eb10a 100644
--- a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
@@ -31,11 +31,11 @@
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Redimensionner"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Ajouter à la réserve"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Retirer de la réserve"</string>
- <string name="dock_forced_resizable" msgid="7429086980048964687">"L\'application peut ne pas fonctionner avec l\'écran partagé"</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"L\'application ne prend pas en charge l\'écran partagé"</string>
- <string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"Cette application ne peut être ouverte que dans une seule fenêtre."</string>
- <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Il est possible que l\'application ne fonctionne pas sur un écran secondaire."</string>
- <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"L\'application ne peut pas être lancée sur des écrans secondaires."</string>
+ <string name="dock_forced_resizable" msgid="7429086980048964687">"L\'appli peut ne pas fonctionner avec l\'écran partagé"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"L\'appli ne prend pas en charge l\'écran partagé"</string>
+ <string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"Cette appli ne peut être ouverte que dans une seule fenêtre."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Il est possible que l\'appli ne fonctionne pas sur un écran secondaire."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"L\'appli ne peut pas être lancée sur des écrans secondaires."</string>
<string name="accessibility_divider" msgid="6407584574218956849">"Séparateur d\'écran partagé"</string>
<string name="divider_title" msgid="1963391955593749442">"Séparateur d\'écran partagé"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Plein écran à la gauche"</string>
@@ -56,7 +56,7 @@
<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>
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"Paramètres pour les bulles de l\'appli <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Menu déroulant"</string>
<string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Replacer sur la pile"</string>
<string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
@@ -73,7 +73,7 @@
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Clavarder en utilisant des bulles"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"Les nouvelles conversations s\'affichent sous forme d\'icônes flottantes (de bulles). Touchez une bulle pour l\'ouvrir. Faites-la glisser pour la déplacer."</string>
<string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Paramètres des bulles"</string>
- <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Toucher Gérer pour désactiver les bulles de cette application"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Toucher Gérer pour désactiver les bulles de cette appli"</string>
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"OK"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Aucune bulle récente"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Les bulles récentes et les bulles ignorées s\'afficheront ici"</string>
@@ -88,29 +88,29 @@
<skip />
<!-- no translation found for bubble_shortcut_long_label (6088437544312894043) -->
<skip />
- <string name="restart_button_description" msgid="4564728020654658478">"Touchez pour redémarrer cette application afin d\'obtenir un meilleur affichage"</string>
- <string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Changer les proportions de cette application dans les paramètres"</string>
+ <string name="restart_button_description" msgid="4564728020654658478">"Touchez pour redémarrer cette appli afin d\'obtenir un meilleur affichage"</string>
+ <string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Changer les proportions de cette appli dans les paramètres"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Modifier les proportions"</string>
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problèmes d\'appareil photo?\nTouchez pour réajuster"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Problème non résolu?\nTouchez pour rétablir"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Aucun problème d\'appareil photo? Touchez pour ignorer."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Voir et en faire plus"</string>
- <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Faites glisser une autre application pour utiliser l\'écran partagé"</string>
- <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Touchez deux fois à côté d\'une application pour la repositionner"</string>
+ <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Faites glisser une autre appli pour utiliser l\'écran partagé"</string>
+ <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Touchez deux fois à côté d\'une appli pour la repositionner"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Développer pour en savoir plus."</string>
<string name="letterbox_restart_dialog_title" msgid="8543049527871033505">"Redémarrer pour un meilleur affichage?"</string>
- <string name="letterbox_restart_dialog_description" msgid="6096946078246557848">"Vous pouvez redémarrer l\'application pour qu\'elle s\'affiche mieux sur votre écran, mais il se peut que vous perdiez votre progression ou toute modification non enregistrée"</string>
+ <string name="letterbox_restart_dialog_description" msgid="6096946078246557848">"Vous pouvez redémarrer l\'appli pour qu\'elle s\'affiche mieux sur votre écran, mais il se peut que vous perdiez votre progression ou toute modification non enregistrée"</string>
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Annuler"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Redémarrer"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Ne plus afficher"</string>
- <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Toucher deux fois pour\ndéplacer cette application"</string>
+ <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Toucher deux fois pour\ndéplacer cette appli"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Agrandir"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Réduire"</string>
<string name="close_button_text" msgid="2913281996024033299">"Fermer"</string>
<string name="back_button_text" msgid="1469718707134137085">"Retour"</string>
<string name="handle_text" msgid="1766582106752184456">"Identifiant"</string>
- <string name="app_icon_text" msgid="2823268023931811747">"Icône de l\'application"</string>
+ <string name="app_icon_text" msgid="2823268023931811747">"Icône de l\'appli"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Plein écran"</string>
<string name="desktop_text" msgid="1077633567027630454">"Mode Bureau"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Écran divisé"</string>
diff --git a/libs/WindowManager/Shell/res/values-nb/strings.xml b/libs/WindowManager/Shell/res/values-nb/strings.xml
index 1161eb608405..27b79019a57a 100644
--- a/libs/WindowManager/Shell/res/values-nb/strings.xml
+++ b/libs/WindowManager/Shell/res/values-nb/strings.xml
@@ -117,7 +117,7 @@
<string name="more_button_text" msgid="3655388105592893530">"Mer"</string>
<string name="float_button_text" msgid="9221657008391364581">"Svevende"</string>
<string name="select_text" msgid="5139083974039906583">"Velg"</string>
- <string name="screenshot_text" msgid="1477704010087786671">"Skjermdump"</string>
+ <string name="screenshot_text" msgid="1477704010087786671">"Skjermbilde"</string>
<string name="close_text" msgid="4986518933445178928">"Lukk"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Lukk menyen"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"Åpne menyen"</string>
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index d143263b69a5..269a58693a24 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -495,9 +495,16 @@
<!-- The radius of the Maximize menu shadow. -->
<dimen name="desktop_mode_maximize_menu_shadow_radius">8dp</dimen>
- <!-- The width of the handle menu in desktop mode. -->
+ <!-- The width of the handle menu in desktop mode. -->
<dimen name="desktop_mode_handle_menu_width">216dp</dimen>
+ <!-- The maximum height of the handle menu in desktop mode. Four pills (52dp each) plus 2dp
+ spacing between them plus 4dp top padding. -->
+ <dimen name="desktop_mode_handle_menu_height">218dp</dimen>
+
+ <!-- The elevation set on the handle menu pills. -->
+ <dimen name="desktop_mode_handle_menu_pill_elevation">1dp</dimen>
+
<!-- The height of the handle menu's "App Info" pill in desktop mode. -->
<dimen name="desktop_mode_handle_menu_app_info_pill_height">52dp</dimen>
@@ -510,8 +517,8 @@
<!-- The height of the handle menu's "Open in browser" pill in desktop mode. -->
<dimen name="desktop_mode_handle_menu_open_in_browser_pill_height">52dp</dimen>
- <!-- The height of the handle menu in desktop mode. -->
- <dimen name="desktop_mode_handle_menu_height">380dp</dimen>
+ <!-- The margin between pills of the handle menu in desktop mode. -->
+ <dimen name="desktop_mode_handle_menu_pill_spacing_margin">2dp</dimen>
<!-- The top margin of the handle menu in desktop mode. -->
<dimen name="desktop_mode_handle_menu_margin_top">4dp</dimen>
@@ -519,9 +526,6 @@
<!-- The start margin of the handle menu in desktop mode. -->
<dimen name="desktop_mode_handle_menu_margin_start">6dp</dimen>
- <!-- The margin between pills of the handle menu in desktop mode. -->
- <dimen name="desktop_mode_handle_menu_pill_spacing_margin">2dp</dimen>
-
<!-- The radius of the caption menu corners. -->
<dimen name="desktop_mode_handle_menu_corner_radius">26dp</dimen>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
index ece02711070e..8467e972526e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
@@ -422,6 +422,12 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
@VisibleForTesting
public void onThresholdCrossed() {
mThresholdCrossed = true;
+ // There was no focus window when calling startBackNavigation, still pilfer pointers so
+ // the next focus window won't receive motion events.
+ if (mBackNavigationInfo == null) {
+ tryPilferPointers();
+ return;
+ }
// Dispatch onBackStarted, only to app callbacks.
// System callbacks will receive onBackStarted when the remote animation starts.
final boolean shouldDispatchToAnimator = shouldDispatchToAnimator();
@@ -542,6 +548,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
if (backNavigationInfo == null) {
ProtoLog.e(WM_SHELL_BACK_PREVIEW, "Received BackNavigationInfo is null.");
cancelLatencyTracking();
+ tryPilferPointers();
return;
}
final int backType = backNavigationInfo.getType();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/HandlerExecutor.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/HandlerExecutor.java
index bfee820870f1..736d954513b1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/HandlerExecutor.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/HandlerExecutor.java
@@ -54,4 +54,11 @@ public class HandlerExecutor implements ShellExecutor {
public boolean hasCallback(Runnable r) {
return mHandler.hasCallbacks(r);
}
+
+ @Override
+ public void assertCurrentThread() {
+ if (!mHandler.getLooper().isCurrentThread()) {
+ throw new IllegalStateException("must be called on " + mHandler);
+ }
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/ShellExecutor.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/ShellExecutor.java
index f729164ed303..2c2961fd4b65 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/ShellExecutor.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/ShellExecutor.java
@@ -96,4 +96,11 @@ public interface ShellExecutor extends Executor {
* See {@link android.os.Handler#hasCallbacks(Runnable)}.
*/
boolean hasCallback(Runnable runnable);
+
+ /**
+ * May throw if the caller is not on the same thread as the executor.
+ */
+ default void assertCurrentThread() {
+ return;
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
index eeceaa943af2..45feff5b0ccc 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
@@ -245,7 +245,10 @@ public abstract class WMShellModule {
return new CaptionWindowDecorViewModel(
context,
mainHandler,
+ mainExecutor,
mainChoreographer,
+ windowManager,
+ shellInit,
taskOrganizer,
displayController,
rootTaskDisplayAreaOrganizer,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1Module.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1Module.java
index 240cf3b96e89..037fbb235bd4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1Module.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1Module.java
@@ -38,12 +38,10 @@ import com.android.wm.shell.common.pip.PipMediaController;
import com.android.wm.shell.common.pip.PipPerfHintController;
import com.android.wm.shell.common.pip.PipSnapAlgorithm;
import com.android.wm.shell.common.pip.PipUiEventLogger;
-import com.android.wm.shell.common.pip.PipUtils;
import com.android.wm.shell.common.pip.SizeSpecSource;
import com.android.wm.shell.dagger.WMShellBaseModule;
import com.android.wm.shell.dagger.WMSingleton;
import com.android.wm.shell.onehanded.OneHandedController;
-import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.pip.PipAnimationController;
import com.android.wm.shell.pip.PipParamsChangedForwarder;
import com.android.wm.shell.pip.PipSurfaceTransactionHelper;
@@ -79,7 +77,7 @@ import java.util.Optional;
public abstract class Pip1Module {
@WMSingleton
@Provides
- static Optional<Pip> providePip1(Context context,
+ static Optional<PipController.PipImpl> providePip1(Context context,
ShellInit shellInit,
ShellCommandHandler shellCommandHandler,
ShellController shellController,
@@ -104,20 +102,16 @@ public abstract class Pip1Module {
TabletopModeController pipTabletopController,
Optional<OneHandedController> oneHandedController,
@ShellMainThread ShellExecutor mainExecutor) {
- if (PipUtils.isPip2ExperimentEnabled()) {
- return Optional.empty();
- } else {
- return Optional.ofNullable(PipController.create(
- context, shellInit, shellCommandHandler, shellController,
- displayController, pipAnimationController, pipAppOpsListener,
- pipBoundsAlgorithm,
- pipKeepClearAlgorithm, pipBoundsState, pipDisplayLayoutState,
- pipMotionHelper, pipMediaController, phonePipMenuController, pipTaskOrganizer,
- pipTransitionState, pipTouchHandler, pipTransitionController,
- windowManagerShellWrapper, taskStackListener, pipParamsChangedForwarder,
- displayInsetsController, pipTabletopController, oneHandedController,
- mainExecutor));
- }
+ return Optional.ofNullable(PipController.create(
+ context, shellInit, shellCommandHandler, shellController,
+ displayController, pipAnimationController, pipAppOpsListener,
+ pipBoundsAlgorithm,
+ pipKeepClearAlgorithm, pipBoundsState, pipDisplayLayoutState,
+ pipMotionHelper, pipMediaController, phonePipMenuController, pipTaskOrganizer,
+ pipTransitionState, pipTouchHandler, pipTransitionController,
+ windowManagerShellWrapper, taskStackListener, pipParamsChangedForwarder,
+ displayInsetsController, pipTabletopController, oneHandedController,
+ mainExecutor));
}
// Handler is used by Icon.loadDrawableAsync
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java
index 696831747865..ea7e9685dd92 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java
@@ -81,6 +81,16 @@ public abstract class Pip2Module {
@WMSingleton
@Provides
+ static Optional<PipController.PipImpl> providePip2(Optional<PipController> pipController) {
+ if (pipController.isEmpty()) {
+ return Optional.empty();
+ } else {
+ return Optional.ofNullable(pipController.get().getPipImpl());
+ }
+ }
+
+ @WMSingleton
+ @Provides
static Optional<PipController> providePipController(Context context,
ShellInit shellInit,
ShellCommandHandler shellCommandHandler,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/PipModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/PipModule.java
index f2631eff890d..a3afe7860f2e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/PipModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/PipModule.java
@@ -18,12 +18,16 @@ package com.android.wm.shell.dagger.pip;
import com.android.wm.shell.common.pip.PipUtils;
import com.android.wm.shell.dagger.WMSingleton;
+import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.pip.PipTransitionController;
+import com.android.wm.shell.pip2.phone.PipController;
import com.android.wm.shell.pip2.phone.PipTransition;
import dagger.Module;
import dagger.Provides;
+import java.util.Optional;
+
/**
* Provides dependencies for external components / modules reference PiP and extracts away the
* selection of legacy and new PiP implementation.
@@ -44,4 +48,17 @@ public abstract class PipModule {
return legacyPipTransition;
}
}
+
+ @WMSingleton
+ @Provides
+ static Optional<Pip> providePip(
+ Optional<com.android.wm.shell.pip.phone.PipController.PipImpl> pip1,
+ Optional<PipController.PipImpl> pip2) {
+ if (PipUtils.isPip2ExperimentEnabled()) {
+ return Optional.ofNullable(pip2.orElse(null));
+
+ } else {
+ return Optional.ofNullable(pip1.orElse(null));
+ }
+ }
}
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 18157d6255e3..580724666949 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
@@ -159,18 +159,6 @@ class DesktopTasksController(
}
}
- private val transitionAreaHeight
- get() =
- context.resources.getDimensionPixelSize(
- com.android.wm.shell.R.dimen.desktop_mode_fullscreen_from_desktop_height
- )
-
- private val transitionAreaWidth
- get() =
- context.resources.getDimensionPixelSize(
- com.android.wm.shell.R.dimen.desktop_mode_transition_area_width
- )
-
/** Task id of the task currently being dragged from fullscreen/split. */
val draggingTaskId
get() = dragToDesktopTransitionHandler.draggingTaskId
@@ -229,6 +217,15 @@ class DesktopTasksController(
dragToDesktopTransitionHandler.setSplitScreenController(controller)
}
+ /** Returns the transition type for the given remote transition. */
+ private fun transitionType(remoteTransition: RemoteTransition?): Int {
+ if (remoteTransition == null) {
+ ProtoLog.v(WM_SHELL_DESKTOP_MODE, "DesktopTasksController: remoteTransition is null")
+ return TRANSIT_NONE
+ }
+ return TRANSIT_TO_FRONT
+ }
+
/** Show all tasks, that are part of the desktop, on top of launcher */
fun showDesktopApps(displayId: Int, remoteTransition: RemoteTransition? = null) {
ProtoLog.v(WM_SHELL_DESKTOP_MODE, "DesktopTasksController: showDesktopApps")
@@ -236,8 +233,7 @@ class DesktopTasksController(
bringDesktopAppsToFront(displayId, wct)
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
- // TODO(b/309014605): ensure remote transition is supplied once state is introduced
- val transitionType = if (remoteTransition == null) TRANSIT_NONE else TRANSIT_TO_FRONT
+ val transitionType = transitionType(remoteTransition)
val handler =
remoteTransition?.let {
OneShotRemoteHandler(transitions.mainExecutor, remoteTransition)
@@ -776,12 +772,13 @@ class DesktopTasksController(
newTaskIdInFront ?: "null"
)
- if (Flags.enableDesktopWindowingWallpaperActivity()) {
+ // Move home to front, ensures that we go back home when all desktop windows are closed
+ moveHomeTask(wct, toTop = true)
+
+ // Currently, we only handle the desktop on the default display really.
+ if (displayId == DEFAULT_DISPLAY && Flags.enableDesktopWindowingWallpaperActivity()) {
// Add translucent wallpaper activity to show the wallpaper underneath
addWallpaperActivity(wct)
- } else {
- // Move home to front
- moveHomeTask(wct, toTop = true)
}
val nonMinimizedTasksOrderedFrontToBack =
@@ -1110,6 +1107,10 @@ class DesktopTasksController(
if (useDesktopOverrideDensity()) {
wct.setDensityDpi(taskInfo.token, getDefaultDensityDpi())
}
+ if (desktopModeTaskRepository.isOnlyVisibleNonClosingTask(taskInfo.taskId)) {
+ // Remove wallpaper activity when leaving desktop mode
+ removeWallpaperActivity(wct)
+ }
}
/**
@@ -1125,6 +1126,10 @@ class DesktopTasksController(
// The task's density may have been overridden in freeform; revert it here as we don't
// want it overridden in multi-window.
wct.setDensityDpi(taskInfo.token, getDefaultDensityDpi())
+ if (desktopModeTaskRepository.isOnlyVisibleNonClosingTask(taskInfo.taskId)) {
+ // Remove wallpaper activity when leaving desktop mode
+ removeWallpaperActivity(wct)
+ }
}
/** Returns the ID of the Task that will be minimized, or null if no task will be minimized. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/docs/debugging.md b/libs/WindowManager/Shell/src/com/android/wm/shell/docs/debugging.md
index 3572d161f5b9..84f6af4125b8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/docs/debugging.md
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/docs/debugging.md
@@ -68,7 +68,7 @@ adb shell dumpsys SurfaceFlinger
## Tracing global SurfaceControl transaction updates
While Winscope traces are very useful, it sometimes doesn't give you enough information about which
-part of the code is initiating the transaction updates. In such cases, it can be helpful to get
+part of the code is initiating the transaction updates. In such cases, it can be helpful to get
stack traces when specific surface transaction calls are made, which is possible by enabling the
following system properties for example:
```shell
@@ -81,9 +81,11 @@ adb logcat -s "SurfaceControlRegistry"
# Disabling logging
adb shell setprop persist.wm.debug.sc.tx.log_match_call \"\"
adb shell setprop persist.wm.debug.sc.tx.log_match_name \"\"
-adb reboot
```
+A reboot is required to enable the logging. Once enabled, reboot is not needed to update the
+properties.
+
It is not necessary to set both `log_match_call` and `log_match_name`, but note logs can be quite
noisy if unfiltered.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
index e0b08668b1d4..e00353d6ac82 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
@@ -302,7 +302,7 @@ public class DragAndDropController implements RemoteCallable<DragAndDropControll
break;
}
}
- if (pd == null || !pd.isHandlingDrag) {
+ if (pd == null || pd.activeDragCount <= 0 || !pd.isHandlingDrag) {
// Not currently dragging
return;
}
@@ -333,9 +333,10 @@ public class DragAndDropController implements RemoteCallable<DragAndDropControll
mActiveDragDisplay = displayId;
pd.isHandlingDrag = DragUtils.canHandleDrag(event);
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP,
- "Clip description: handlingDrag=%b itemCount=%d mimeTypes=%s",
+ "Clip description: handlingDrag=%b itemCount=%d mimeTypes=%s flags=%s",
pd.isHandlingDrag, event.getClipData().getItemCount(),
- DragUtils.getMimeTypesConcatenated(description));
+ DragUtils.getMimeTypesConcatenated(description),
+ DragUtils.dragFlagsToString(event.getDragFlags()));
}
if (!pd.isHandlingDrag) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
index f0514e3e49f5..e4aa115347eb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
@@ -293,6 +293,8 @@ public class DragLayout extends LinearLayout
int bgColor1 = getResizingBackgroundColor(taskInfo1).toArgb();
mDropZoneView1.setAppInfo(bgColor1, icon1);
mDropZoneView2.setAppInfo(bgColor1, icon1);
+ mDropZoneView1.setForceIgnoreBottomMargin(false);
+ mDropZoneView2.setForceIgnoreBottomMargin(false);
updateDropZoneSizes(null, null); // passing null splits the views evenly
} else {
// We use the first drop zone to show the fullscreen highlight, and don't need
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragUtils.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragUtils.java
index e215870f1894..22cfa328bfda 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragUtils.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragUtils.java
@@ -19,16 +19,28 @@ package com.android.wm.shell.draganddrop;
import static android.content.ClipDescription.MIMETYPE_APPLICATION_ACTIVITY;
import static android.content.ClipDescription.MIMETYPE_APPLICATION_SHORTCUT;
import static android.content.ClipDescription.MIMETYPE_APPLICATION_TASK;
+import static android.view.View.DRAG_FLAG_ACCESSIBILITY_ACTION;
+import static android.view.View.DRAG_FLAG_GLOBAL;
+import static android.view.View.DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION;
+import static android.view.View.DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION;
+import static android.view.View.DRAG_FLAG_GLOBAL_SAME_APPLICATION;
+import static android.view.View.DRAG_FLAG_GLOBAL_URI_READ;
+import static android.view.View.DRAG_FLAG_GLOBAL_URI_WRITE;
+import static android.view.View.DRAG_FLAG_HIDE_CALLING_TASK_ON_DRAG_START;
+import static android.view.View.DRAG_FLAG_OPAQUE;
+import static android.view.View.DRAG_FLAG_REQUEST_SURFACE_FOR_RETURN_ANIMATION;
+import static android.view.View.DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG;
import android.app.PendingIntent;
import android.content.ClipData;
import android.content.ClipDescription;
import android.view.DragEvent;
-import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import java.util.StringJoiner;
+
/** Collection of utility classes for handling drag and drop. */
public class DragUtils {
private static final String TAG = "DragUtils";
@@ -76,7 +88,7 @@ public class DragUtils {
*/
@Nullable
public static PendingIntent getLaunchIntent(@NonNull ClipData data, int dragFlags) {
- if ((dragFlags & View.DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG) == 0) {
+ if ((dragFlags & DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG) == 0) {
// Disallow launching the intent if the app does not want to delegate it to the system
return null;
}
@@ -105,4 +117,35 @@ public class DragUtils {
}
return mimeTypes;
}
+
+ /**
+ * Returns the string description of the given {@param dragFlags}.
+ */
+ public static String dragFlagsToString(int dragFlags) {
+ StringJoiner str = new StringJoiner("|");
+ if ((dragFlags & DRAG_FLAG_GLOBAL) != 0) {
+ str.add("GLOBAL");
+ } else if ((dragFlags & DRAG_FLAG_GLOBAL_URI_READ) != 0) {
+ str.add("GLOBAL_URI_READ");
+ } else if ((dragFlags & DRAG_FLAG_GLOBAL_URI_WRITE) != 0) {
+ str.add("GLOBAL_URI_WRITE");
+ } else if ((dragFlags & DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION) != 0) {
+ str.add("GLOBAL_PERSISTABLE_URI_PERMISSION");
+ } else if ((dragFlags & DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION) != 0) {
+ str.add("GLOBAL_PREFIX_URI_PERMISSION");
+ } else if ((dragFlags & DRAG_FLAG_OPAQUE) != 0) {
+ str.add("OPAQUE");
+ } else if ((dragFlags & DRAG_FLAG_ACCESSIBILITY_ACTION) != 0) {
+ str.add("ACCESSIBILITY_ACTION");
+ } else if ((dragFlags & DRAG_FLAG_REQUEST_SURFACE_FOR_RETURN_ANIMATION) != 0) {
+ str.add("REQUEST_SURFACE_FOR_RETURN_ANIMATION");
+ } else if ((dragFlags & DRAG_FLAG_GLOBAL_SAME_APPLICATION) != 0) {
+ str.add("GLOBAL_SAME_APPLICATION");
+ } else if ((dragFlags & DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG) != 0) {
+ str.add("START_INTENT_SENDER_ON_UNHANDLED_DRAG");
+ } else if ((dragFlags & DRAG_FLAG_HIDE_CALLING_TASK_ON_DRAG_START) != 0) {
+ str.add("HIDE_CALLING_TASK_ON_DRAG_START");
+ }
+ return str.toString();
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java
index b6b49a87484e..18cd2d84d32d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java
@@ -151,6 +151,10 @@ public class DropZoneView extends FrameLayout {
/** Ignores the bottom margin provided by the insets. */
public void setForceIgnoreBottomMargin(boolean ignoreBottomMargin) {
+ if (DEBUG_LAYOUT) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP,
+ "setForceIgnoreBottomMargin: ignore=%b", ignoreBottomMargin);
+ }
mIgnoreBottomMargin = ignoreBottomMargin;
if (mMarginPercent > 0) {
mMarginView.invalidate();
@@ -159,8 +163,14 @@ public class DropZoneView extends FrameLayout {
/** Sets the bottom inset so the drop zones are above bottom navigation. */
public void setBottomInset(float bottom) {
+ if (DEBUG_LAYOUT) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "setBottomInset: inset=%f",
+ bottom);
+ }
mBottomInset = bottom;
- ((LayoutParams) mSplashScreenView.getLayoutParams()).bottomMargin = (int) bottom;
+ final LayoutParams lp = (LayoutParams) mSplashScreenView.getLayoutParams();
+ lp.bottomMargin = (int) bottom;
+ mSplashScreenView.setLayoutParams(lp);
if (mMarginPercent > 0) {
mMarginView.invalidate();
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index d1d82755d12c..0cb7e17e41e9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -374,7 +374,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb
* Instantiates {@link PipController}, returns {@code null} if the feature not supported.
*/
@Nullable
- public static Pip create(Context context,
+ public static PipImpl create(Context context,
ShellInit shellInit,
ShellCommandHandler shellCommandHandler,
ShellController shellController,
@@ -1177,7 +1177,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb
/**
* The interface for calls from outside the Shell, within the host process.
*/
- private class PipImpl implements Pip {
+ public class PipImpl implements Pip {
@Override
public void expandPip() {
mMainExecutor.execute(() -> {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java
index 06adad626e9f..c12219c8a9e0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java
@@ -55,6 +55,8 @@ import com.android.wm.shell.common.pip.PipBoundsAlgorithm;
import com.android.wm.shell.common.pip.PipBoundsState;
import com.android.wm.shell.common.pip.PipDisplayLayoutState;
import com.android.wm.shell.common.pip.PipUtils;
+import com.android.wm.shell.pip.Pip;
+import com.android.wm.shell.pip.PipTransitionController;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.sysui.ConfigurationChangeListener;
import com.android.wm.shell.sysui.ShellCommandHandler;
@@ -62,6 +64,8 @@ import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.sysui.ShellInit;
import java.io.PrintWriter;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
/**
* Manages the picture-in-picture (PIP) UI and states for Phones.
@@ -86,6 +90,8 @@ public class PipController implements ConfigurationChangeListener,
private final ShellTaskOrganizer mShellTaskOrganizer;
private final PipTransitionState mPipTransitionState;
private final ShellExecutor mMainExecutor;
+ private final PipImpl mImpl;
+ private Consumer<Boolean> mOnIsInPipStateChangedListener;
// Wrapper for making Binder calls into PiP animation listener hosted in launcher's Recents.
private PipAnimationListener mPipRecentsAnimationListener;
@@ -140,6 +146,7 @@ public class PipController implements ConfigurationChangeListener,
mPipTransitionState = pipTransitionState;
mPipTransitionState.addPipTransitionStateChangedListener(this);
mMainExecutor = mainExecutor;
+ mImpl = new PipImpl();
if (PipUtils.isPip2ExperimentEnabled()) {
shellInit.addInitCallback(this::onInit, this);
@@ -174,6 +181,10 @@ public class PipController implements ConfigurationChangeListener,
pipTransitionState, mainExecutor);
}
+ public PipImpl getPipImpl() {
+ return mImpl;
+ }
+
private void onInit() {
mShellCommandHandler.addDumpCallback(this::dump, this);
// Ensure that we have the display info in case we get calls to update the bounds before the
@@ -310,22 +321,29 @@ public class PipController implements ConfigurationChangeListener,
@Override
public void onPipTransitionStateChanged(@PipTransitionState.TransitionState int oldState,
@PipTransitionState.TransitionState int newState, @Nullable Bundle extra) {
- if (newState == PipTransitionState.SWIPING_TO_PIP) {
- Preconditions.checkState(extra != null,
- "No extra bundle for " + mPipTransitionState);
-
- SurfaceControl overlay = extra.getParcelable(
- SWIPE_TO_PIP_OVERLAY, SurfaceControl.class);
- Rect appBounds = extra.getParcelable(
- SWIPE_TO_PIP_APP_BOUNDS, Rect.class);
-
- Preconditions.checkState(appBounds != null,
- "App bounds can't be null for " + mPipTransitionState);
- mPipTransitionState.setSwipePipToHomeState(overlay, appBounds);
- } else if (newState == PipTransitionState.ENTERED_PIP) {
- if (mPipTransitionState.isInSwipePipToHomeTransition()) {
- mPipTransitionState.resetSwipePipToHomeState();
- }
+ switch (newState) {
+ case PipTransitionState.SWIPING_TO_PIP:
+ Preconditions.checkState(extra != null,
+ "No extra bundle for " + mPipTransitionState);
+
+ SurfaceControl overlay = extra.getParcelable(
+ SWIPE_TO_PIP_OVERLAY, SurfaceControl.class);
+ Rect appBounds = extra.getParcelable(
+ SWIPE_TO_PIP_APP_BOUNDS, Rect.class);
+
+ Preconditions.checkState(appBounds != null,
+ "App bounds can't be null for " + mPipTransitionState);
+ mPipTransitionState.setSwipePipToHomeState(overlay, appBounds);
+ break;
+ case PipTransitionState.ENTERED_PIP:
+ if (mPipTransitionState.isInSwipePipToHomeTransition()) {
+ mPipTransitionState.resetSwipePipToHomeState();
+ }
+ mOnIsInPipStateChangedListener.accept(true /* inPip */);
+ break;
+ case PipTransitionState.EXITED_PIP:
+ mOnIsInPipStateChangedListener.accept(false /* inPip */);
+ break;
}
}
@@ -355,6 +373,53 @@ public class PipController implements ConfigurationChangeListener,
mPipTransitionState.dump(pw, innerPrefix);
}
+ private void setOnIsInPipStateChangedListener(Consumer<Boolean> callback) {
+ mOnIsInPipStateChangedListener = callback;
+ if (mOnIsInPipStateChangedListener != null) {
+ callback.accept(mPipTransitionState.isInPip());
+ }
+ }
+
+ /**
+ * The interface for calls from outside the Shell, within the host process.
+ */
+ public class PipImpl implements Pip {
+ @Override
+ public void expandPip() {}
+
+ @Override
+ public void onSystemUiStateChanged(boolean isSysUiStateValid, long flag) {}
+
+ @Override
+ public void setOnIsInPipStateChangedListener(Consumer<Boolean> callback) {
+ mMainExecutor.execute(() -> {
+ PipController.this.setOnIsInPipStateChangedListener(callback);
+ });
+ }
+
+ @Override
+ public void addPipExclusionBoundsChangeListener(Consumer<Rect> listener) {
+ mMainExecutor.execute(() -> {
+ mPipBoundsState.addPipExclusionBoundsChangeCallback(listener);
+ });
+ }
+
+ @Override
+ public void removePipExclusionBoundsChangeListener(Consumer<Rect> listener) {
+ mMainExecutor.execute(() -> {
+ mPipBoundsState.removePipExclusionBoundsChangeCallback(listener);
+ });
+ }
+
+ @Override
+ public void showPictureInPictureMenu() {}
+
+ @Override
+ public void registerPipTransitionCallback(
+ PipTransitionController.PipTransitionCallback callback,
+ Executor executor) {}
+ }
+
/**
* The interface for calls from outside the host process.
*/
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java
index e277a8dbeb13..ea02de9d9704 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java
@@ -816,6 +816,26 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
mPipBoundsState.getMotionBoundsState().onPhysicsAnimationEnded();
mSpringingToTouch = false;
mDismissalPending = false;
+
+ // Check whether new bounds after fling imply we need to update stash state too.
+ stashEndActionIfNeeded();
+ }
+
+ private void stashEndActionIfNeeded() {
+ boolean isStashing = mPipBoundsState.getBounds().right > mPipBoundsState
+ .getDisplayBounds().width() || mPipBoundsState.getBounds().left < 0;
+ if (!isStashing) {
+ return;
+ }
+
+ if (mPipBoundsState.getBounds().left < 0
+ && mPipBoundsState.getStashedState() != STASH_TYPE_LEFT) {
+ mPipBoundsState.setStashed(STASH_TYPE_LEFT);
+ } else if (mPipBoundsState.getBounds().left >= 0
+ && mPipBoundsState.getStashedState() != STASH_TYPE_RIGHT) {
+ mPipBoundsState.setStashed(STASH_TYPE_RIGHT);
+ }
+ mMenuController.hideMenu();
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java
index 0c4ed268fd28..53b80e8b7542 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java
@@ -106,9 +106,6 @@ public class PipTouchHandler implements PipTransitionState.PipTransitionStateCha
private float mStashVelocityThreshold;
- // The reference inset bounds, used to determine the dismiss fraction
- private final Rect mInsetBounds = new Rect();
-
// Used to workaround an issue where the WM rotation happens before we are notified, allowing
// us to send stale bounds
private int mDeferResizeToNormalBoundsUntilRotation = -1;
@@ -206,17 +203,10 @@ public class PipTouchHandler implements PipTransitionState.PipTransitionStateCha
mMotionHelper, mainExecutor);
mTouchState = new PipTouchState(ViewConfiguration.get(context),
() -> {
- if (mPipBoundsState.isStashed()) {
- animateToUnStashedState();
- mPipUiEventLogger.log(
- PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_STASH_UNSTASHED);
- mPipBoundsState.setStashed(STASH_TYPE_NONE);
- } else {
- mMenuController.showMenuWithPossibleDelay(MENU_STATE_FULL,
- mPipBoundsState.getBounds(), true /* allowMenuTimeout */,
- willResizeMenu(),
- shouldShowResizeHandle());
- }
+ mMenuController.showMenuWithPossibleDelay(MENU_STATE_FULL,
+ mPipBoundsState.getBounds(), true /* allowMenuTimeout */,
+ willResizeMenu(),
+ shouldShowResizeHandle());
},
menuController::hideMenu,
mainExecutor);
@@ -438,7 +428,6 @@ public class PipTouchHandler implements PipTransitionState.PipTransitionStateCha
mPipBoundsState.setNormalMovementBounds(normalMovementBounds);
mPipBoundsState.setExpandedMovementBounds(expandedMovementBounds);
mDisplayRotation = displayRotation;
- mInsetBounds.set(insetBounds);
updateMovementBounds();
mMovementBoundsExtraOffsets = extraOffset;
@@ -748,10 +737,13 @@ public class PipTouchHandler implements PipTransitionState.PipTransitionStateCha
final Rect pipBounds = mPipBoundsState.getBounds();
final boolean onLeftEdge = pipBounds.left < mPipBoundsState.getDisplayBounds().left;
final Rect unStashedBounds = new Rect(0, pipBounds.top, 0, pipBounds.bottom);
- unStashedBounds.left = onLeftEdge ? mInsetBounds.left
- : mInsetBounds.right - pipBounds.width();
- unStashedBounds.right = onLeftEdge ? mInsetBounds.left + pipBounds.width()
- : mInsetBounds.right;
+
+ Rect insetBounds = new Rect();
+ mPipBoundsAlgorithm.getInsetBounds(insetBounds);
+ unStashedBounds.left = onLeftEdge ? insetBounds.left
+ : insetBounds.right - pipBounds.width();
+ unStashedBounds.right = onLeftEdge ? insetBounds.left + pipBounds.width()
+ : insetBounds.right;
mMotionHelper.animateToUnStashedBounds(unStashedBounds);
}
@@ -899,8 +891,7 @@ public class PipTouchHandler implements PipTransitionState.PipTransitionStateCha
// Reset the touch state on up before the fling settles
mTouchState.reset();
if (mEnableStash && shouldStash(vel, getPossiblyMotionBounds())) {
- // mMotionHelper.stashToEdge(vel.x, vel.y,
- // this::stashEndAction /* endAction */);
+ mMotionHelper.stashToEdge(vel.x, vel.y, null /* endAction */);
} else {
if (mPipBoundsState.isStashed()) {
// Reset stashed state if previously stashed
@@ -1030,8 +1021,10 @@ public class PipTouchHandler implements PipTransitionState.PipTransitionStateCha
* resized.
*/
private void updateMovementBounds() {
+ Rect insetBounds = new Rect();
+ mPipBoundsAlgorithm.getInsetBounds(insetBounds);
mPipBoundsAlgorithm.getMovementBounds(mPipBoundsState.getBounds(),
- mInsetBounds, mPipBoundsState.getMovementBounds(), mIsImeShowing ? mImeHeight : 0);
+ insetBounds, mPipBoundsState.getMovementBounds(), mIsImeShowing ? mImeHeight : 0);
mMotionHelper.onMovementBoundsChanged();
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTaskController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTaskController.java
index a126cbe41b00..9750d3ec99f5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTaskController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTaskController.java
@@ -535,7 +535,8 @@ public class TaskViewTaskController implements ShellTaskOrganizer.TaskListener {
WindowContainerTransaction wct = new WindowContainerTransaction();
if (mCaptionInsets != null) {
wct.addInsetsSource(mTaskToken, mCaptionInsetsOwner, 0,
- WindowInsets.Type.captionBar(), mCaptionInsets, null /* boundingRects */);
+ WindowInsets.Type.captionBar(), mCaptionInsets, null /* boundingRects */,
+ 0 /* flags */);
} else {
wct.removeInsetsSource(mTaskToken, mCaptionInsetsOwner, 0,
WindowInsets.Type.captionBar());
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
index 73b32a24246a..778478405dda 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
@@ -19,6 +19,7 @@ package com.android.wm.shell.transition;
import static android.app.ActivityOptions.ANIM_CLIP_REVEAL;
import static android.app.ActivityOptions.ANIM_CUSTOM;
import static android.app.ActivityOptions.ANIM_NONE;
+import static android.app.ActivityOptions.ANIM_FROM_STYLE;
import static android.app.ActivityOptions.ANIM_OPEN_CROSS_PROFILE_APPS;
import static android.app.ActivityOptions.ANIM_SCALE_UP;
import static android.app.ActivityOptions.ANIM_SCENE_TRANSITION;
@@ -40,6 +41,7 @@ import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECI
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE;
import static android.view.WindowManager.TRANSIT_RELAUNCH;
+import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.window.TransitionInfo.FLAG_CROSS_PROFILE_OWNER_THUMBNAIL;
import static android.window.TransitionInfo.FLAG_CROSS_PROFILE_WORK_THUMBNAIL;
import static android.window.TransitionInfo.FLAG_DISPLAY_HAS_ALERT_WINDOWS;
@@ -62,6 +64,7 @@ import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITI
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.TransitionAnimationHelper.getTransitionTypeFromInfo;
+import static com.android.wm.shell.transition.TransitionAnimationHelper.isCoveredByOpaqueFullscreenChange;
import static com.android.wm.shell.transition.TransitionAnimationHelper.loadAttributeAnimation;
import android.animation.Animator;
@@ -352,6 +355,7 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
continue;
}
final boolean isTask = change.getTaskInfo() != null;
+ final boolean isFreeform = isTask && change.getTaskInfo().isFreeform();
final int mode = change.getMode();
boolean isSeamlessDisplayChange = false;
@@ -458,6 +462,16 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
final int layer = zSplitLine + numChanges - i;
startTransaction.setLayer(change.getLeash(), layer);
}
+ } else if (!isCoveredByOpaqueFullscreenChange(info, change)
+ && isFreeform
+ && TransitionUtil.isOpeningMode(type)
+ && change.getMode() == TRANSIT_TO_BACK) {
+ // Reparent the minimize-change to the root task so the minimizing Task
+ // isn't shown in front of other Tasks.
+ mRootTDAOrganizer.reparentToDisplayArea(
+ change.getTaskInfo().displayId,
+ change.getLeash(),
+ startTransaction);
} else if (isOnlyTranslucent && TransitionUtil.isOpeningType(info.getType())
&& TransitionUtil.isClosingType(mode)) {
// If there is a closing translucent task in an OPENING transition, we will
@@ -985,7 +999,8 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
final int animType = options.getType();
return animType == ANIM_CUSTOM || animType == ANIM_SCALE_UP
|| animType == ANIM_THUMBNAIL_SCALE_UP || animType == ANIM_THUMBNAIL_SCALE_DOWN
- || animType == ANIM_CLIP_REVEAL || animType == ANIM_OPEN_CROSS_PROFILE_APPS;
+ || animType == ANIM_CLIP_REVEAL || animType == ANIM_OPEN_CROSS_PROFILE_APPS
+ || animType == ANIM_FROM_STYLE;
}
private static void applyTransformation(long time, SurfaceControl.Transaction t,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java
index a5f071af6973..75e7ddf53f9f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java
@@ -36,6 +36,7 @@ import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITI
import android.annotation.ColorInt;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.WindowConfiguration;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
@@ -72,6 +73,9 @@ public class TransitionAnimationHelper {
final int changeFlags = change.getFlags();
final boolean enter = TransitionUtil.isOpeningType(changeMode);
final boolean isTask = change.getTaskInfo() != null;
+ final boolean isFreeform = isTask && change.getTaskInfo().isFreeform();
+ final boolean isCoveredByOpaqueFullscreenChange =
+ isCoveredByOpaqueFullscreenChange(info, change);
final TransitionInfo.AnimationOptions options;
if (Flags.moveAnimationOptionsToChange()) {
options = change.getAnimationOptions();
@@ -107,6 +111,24 @@ public class TransitionAnimationHelper {
animAttr = enter
? R.styleable.WindowAnimation_wallpaperCloseEnterAnimation
: R.styleable.WindowAnimation_wallpaperCloseExitAnimation;
+ } else if (!isCoveredByOpaqueFullscreenChange
+ && isFreeform
+ && TransitionUtil.isOpeningMode(type)
+ && change.getMode() == TRANSIT_TO_BACK) {
+ // Set translucent here so TransitionAnimation loads the appropriate animations for
+ // translucent activities and tasks later
+ translucent = (changeFlags & FLAG_TRANSLUCENT) != 0;
+ // The main Task is launching or being brought to front, this Task is being minimized
+ animAttr = R.styleable.WindowAnimation_activityCloseExitAnimation;
+ } else if (!isCoveredByOpaqueFullscreenChange
+ && isFreeform
+ && type == TRANSIT_TO_FRONT
+ && change.getMode() == TRANSIT_TO_FRONT) {
+ // Set translucent here so TransitionAnimation loads the appropriate animations for
+ // translucent activities and tasks later
+ translucent = (changeFlags & FLAG_TRANSLUCENT) != 0;
+ // Bring the minimized Task back to front
+ animAttr = R.styleable.WindowAnimation_activityOpenEnterAnimation;
} else if (type == TRANSIT_OPEN) {
// We will translucent open animation for translucent activities and tasks. Choose
// WindowAnimation_activityOpenEnterAnimation and set translucent here, then
@@ -417,4 +439,25 @@ public class TransitionAnimationHelper {
return edgeExtensionLayer;
}
+
+ /**
+ * Returns whether there is an opaque fullscreen Change positioned in front of the given Change
+ * in the given TransitionInfo.
+ */
+ static boolean isCoveredByOpaqueFullscreenChange(
+ TransitionInfo info, TransitionInfo.Change change) {
+ // TransitionInfo#getChanges() are ordered from front to back
+ for (TransitionInfo.Change coveringChange : info.getChanges()) {
+ if (coveringChange == change) {
+ return false;
+ }
+ if ((coveringChange.getFlags() & FLAG_TRANSLUCENT) == 0
+ && coveringChange.getTaskInfo() != null
+ && coveringChange.getTaskInfo().getWindowingMode()
+ == WindowConfiguration.WINDOWING_MODE_FULLSCREEN) {
+ return true;
+ }
+ }
+ return false;
+ }
}
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 21307a2edae0..8d53bebba7bb 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
@@ -31,12 +31,14 @@ import static android.view.WindowManager.fixScale;
import static android.view.WindowManager.transitTypeToString;
import static android.window.TransitionInfo.FLAGS_IS_NON_APP_WINDOW;
import static android.window.TransitionInfo.FLAG_BACK_GESTURE_ANIMATED;
+import static android.window.TransitionInfo.FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY;
import static android.window.TransitionInfo.FLAG_IS_BEHIND_STARTING_WINDOW;
import static android.window.TransitionInfo.FLAG_IS_OCCLUDED;
import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
import static android.window.TransitionInfo.FLAG_NO_ANIMATION;
import static android.window.TransitionInfo.FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT;
+import static com.android.window.flags.Flags.enforceShellThreadModel;
import static com.android.window.flags.Flags.ensureWallpaperInTransitions;
import static com.android.systemui.shared.Flags.returnAnimationFrameworkLibrary;
import static com.android.wm.shell.shared.TransitionUtil.isClosingType;
@@ -806,14 +808,16 @@ public class Transitions implements RemoteCallable<Transitions>,
final int changeSize = info.getChanges().size();
boolean taskChange = false;
boolean transferStartingWindow = false;
- int noAnimationBehindStartingWindow = 0;
+ int animBehindStartingWindow = 0;
boolean allOccluded = changeSize > 0;
for (int i = changeSize - 1; i >= 0; --i) {
final TransitionInfo.Change change = info.getChanges().get(i);
taskChange |= change.getTaskInfo() != null;
transferStartingWindow |= change.hasFlags(FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT);
- if (change.hasAllFlags(FLAG_IS_BEHIND_STARTING_WINDOW | FLAG_NO_ANIMATION)) {
- noAnimationBehindStartingWindow++;
+ if (change.hasAllFlags(FLAG_IS_BEHIND_STARTING_WINDOW | FLAG_NO_ANIMATION)
+ || change.hasAllFlags(
+ FLAG_IS_BEHIND_STARTING_WINDOW | FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY)) {
+ animBehindStartingWindow++;
}
if (!change.hasFlags(FLAG_IS_OCCLUDED)) {
allOccluded = false;
@@ -831,11 +835,11 @@ public class Transitions implements RemoteCallable<Transitions>,
// There does not need animation when:
// A. Transfer starting window. Apply transfer starting window directly if there is no other
// task change. Since this is an activity->activity situation, we can detect it by selecting
- // transitions with only 2 changes where
- // 1. neither are tasks, and
+ // transitions with changes where
+ // 1. none are tasks, and
// 2. one is a starting-window recipient, or all change is behind starting window.
- if (!taskChange && (transferStartingWindow || noAnimationBehindStartingWindow == changeSize)
- && changeSize == 2
+ if (!taskChange && (transferStartingWindow || animBehindStartingWindow == changeSize)
+ && changeSize >= 1
// B. It's visibility change if the TRANSIT_TO_BACK/TO_FRONT happened when all
// changes are underneath another change.
|| ((info.getType() == TRANSIT_TO_BACK || info.getType() == TRANSIT_TO_FRONT)
@@ -921,9 +925,12 @@ public class Transitions implements RemoteCallable<Transitions>,
}
// An existing animation is playing, so see if we can merge.
final ActiveTransition playing = track.mActiveTransition;
+ final IBinder playingToken = playing.mToken;
+ final IBinder readyToken = ready.mToken;
+
if (ready.mAborted) {
// record as merged since it is no-op. Calls back into processReadyQueue
- onMerged(playing, ready);
+ onMerged(playingToken, readyToken);
return;
}
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "Transition %s ready while"
@@ -931,14 +938,31 @@ public class Transitions implements RemoteCallable<Transitions>,
+ " in case they can be merged", ready, playing);
mTransitionTracer.logMergeRequested(ready.mInfo.getDebugId(), playing.mInfo.getDebugId());
playing.mHandler.mergeAnimation(ready.mToken, ready.mInfo, ready.mStartT,
- playing.mToken, (wct) -> onMerged(playing, ready));
+ playing.mToken, (wct) -> onMerged(playingToken, readyToken));
}
- private void onMerged(@NonNull ActiveTransition playing, @NonNull ActiveTransition merged) {
+ private void onMerged(@NonNull IBinder playingToken, @NonNull IBinder mergedToken) {
+ if (enforceShellThreadModel()) {
+ mMainExecutor.assertCurrentThread();
+ }
+
+ ActiveTransition playing = mKnownTransitions.get(playingToken);
+ if (playing == null) {
+ Log.e(TAG, "Merging into a non-existent transition: " + playingToken);
+ return;
+ }
+
+ ActiveTransition merged = mKnownTransitions.get(mergedToken);
+ if (merged == null) {
+ Log.e(TAG, "Merging a non-existent transition: " + mergedToken);
+ return;
+ }
+
if (playing.getTrack() != merged.getTrack()) {
throw new IllegalStateException("Can't merge across tracks: " + merged + " into "
+ playing);
}
+
final Track track = mTracks.get(playing.getTrack());
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "Transition was merged: %s into %s",
merged, playing);
@@ -1068,13 +1092,17 @@ public class Transitions implements RemoteCallable<Transitions>,
info.releaseAnimSurfaces();
}
- private void onFinish(IBinder token,
- @Nullable WindowContainerTransaction wct) {
+ private void onFinish(IBinder token, @Nullable WindowContainerTransaction wct) {
+ if (enforceShellThreadModel()) {
+ mMainExecutor.assertCurrentThread();
+ }
+
final ActiveTransition active = mKnownTransitions.get(token);
if (active == null) {
Log.e(TAG, "Trying to finish a non-existent transition: " + token);
return;
}
+
final Track track = mTracks.get(active.getTrack());
if (track == null || track.mActiveTransition != active) {
Log.e(TAG, "Trying to finish a non-running transition. Either remote crashed or "
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 95e0d79c212e..b9cb6d3d5007 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
@@ -26,12 +26,20 @@ import static android.view.WindowManager.TRANSIT_CHANGE;
import android.app.ActivityManager.RunningTaskInfo;
import android.content.ContentResolver;
import android.content.Context;
+import android.graphics.Color;
+import android.graphics.Point;
import android.graphics.Rect;
+import android.graphics.Region;
+import android.hardware.input.InputManager;
import android.os.Handler;
+import android.os.RemoteException;
import android.provider.Settings;
+import android.util.Log;
import android.util.SparseArray;
import android.view.Choreographer;
import android.view.Display;
+import android.view.ISystemGestureExclusionListener;
+import android.view.IWindowManager;
import android.view.MotionEvent;
import android.view.SurfaceControl;
import android.view.View;
@@ -45,39 +53,74 @@ import com.android.wm.shell.R;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.freeform.FreeformTaskTransitionStarter;
import com.android.wm.shell.splitscreen.SplitScreenController;
+import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.transition.Transitions;
+import com.android.wm.shell.windowdecor.extension.TaskInfoKt;
/**
* View model for the window decoration with a caption and shadows. Works with
* {@link CaptionWindowDecoration}.
*/
public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
+ private static final String TAG = "CaptionWindowDecorViewModel";
+
private final ShellTaskOrganizer mTaskOrganizer;
+ private final IWindowManager mWindowManager;
private final Context mContext;
private final Handler mMainHandler;
+ private final ShellExecutor mMainExecutor;
private final Choreographer mMainChoreographer;
private final DisplayController mDisplayController;
private final RootTaskDisplayAreaOrganizer mRootTaskDisplayAreaOrganizer;
private final SyncTransactionQueue mSyncQueue;
private final Transitions mTransitions;
+ private final Region mExclusionRegion = Region.obtain();
+ private final InputManager mInputManager;
private TaskOperations mTaskOperations;
+ /**
+ * Whether to pilfer the next motion event to send cancellations to the windows below.
+ * Useful when the caption window is spy and the gesture should be handled by the system
+ * instead of by the app for their custom header content.
+ */
+ private boolean mShouldPilferCaptionEvents;
+
private final SparseArray<CaptionWindowDecoration> mWindowDecorByTaskId = new SparseArray<>();
+ private final ISystemGestureExclusionListener mGestureExclusionListener =
+ new ISystemGestureExclusionListener.Stub() {
+ @Override
+ public void onSystemGestureExclusionChanged(int displayId,
+ Region systemGestureExclusion, Region systemGestureExclusionUnrestricted) {
+ if (mContext.getDisplayId() != displayId) {
+ return;
+ }
+ mMainExecutor.execute(() -> {
+ mExclusionRegion.set(systemGestureExclusion);
+ });
+ }
+ };
+
public CaptionWindowDecorViewModel(
Context context,
Handler mainHandler,
+ ShellExecutor shellExecutor,
Choreographer mainChoreographer,
+ IWindowManager windowManager,
+ ShellInit shellInit,
ShellTaskOrganizer taskOrganizer,
DisplayController displayController,
RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
SyncTransactionQueue syncQueue,
Transitions transitions) {
mContext = context;
+ mMainExecutor = shellExecutor;
mMainHandler = mainHandler;
+ mWindowManager = windowManager;
mMainChoreographer = mainChoreographer;
mTaskOrganizer = taskOrganizer;
mDisplayController = displayController;
@@ -87,6 +130,18 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
if (!Transitions.ENABLE_SHELL_TRANSITIONS) {
mTaskOperations = new TaskOperations(null, mContext, mSyncQueue);
}
+ mInputManager = mContext.getSystemService(InputManager.class);
+
+ shellInit.addInitCallback(this::onInit, this);
+ }
+
+ private void onInit() {
+ try {
+ mWindowManager.registerSystemGestureExclusionListener(mGestureExclusionListener,
+ mContext.getDisplayId());
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to register window manager callbacks", e);
+ }
}
@Override
@@ -178,8 +233,12 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
}
private void setupCaptionColor(RunningTaskInfo taskInfo, CaptionWindowDecoration decoration) {
- final int statusBarColor = taskInfo.taskDescription.getStatusBarColor();
- decoration.setCaptionColor(statusBarColor);
+ if (TaskInfoKt.isTransparentCaptionBarAppearance(taskInfo)) {
+ decoration.setCaptionColor(Color.TRANSPARENT);
+ } else {
+ final int statusBarColor = taskInfo.taskDescription.getStatusBarColor();
+ decoration.setCaptionColor(statusBarColor);
+ }
}
private boolean shouldShowWindowDecor(RunningTaskInfo taskInfo) {
@@ -301,6 +360,49 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
mSyncQueue.queue(wct);
}
}
+ final CaptionWindowDecoration decoration = mWindowDecorByTaskId.get(mTaskId);
+
+ final int actionMasked = e.getActionMasked();
+ final boolean isDown = actionMasked == MotionEvent.ACTION_DOWN;
+ final boolean isUpOrCancel = actionMasked == MotionEvent.ACTION_CANCEL
+ || actionMasked == MotionEvent.ACTION_UP;
+ if (isDown) {
+ final boolean downInCustomizableCaptionRegion =
+ decoration.checkTouchEventInCustomizableRegion(e);
+ final boolean downInExclusionRegion = mExclusionRegion.contains(
+ (int) e.getRawX(), (int) e.getRawY());
+ final boolean isTransparentCaption =
+ TaskInfoKt.isTransparentCaptionBarAppearance(decoration.mTaskInfo);
+ // MotionEvent's coordinates are relative to view, we want location in window
+ // to offset position relative to caption as a whole.
+ int[] viewLocation = new int[2];
+ v.getLocationInWindow(viewLocation);
+ final boolean isResizeEvent = decoration.shouldResizeListenerHandleEvent(e,
+ new Point(viewLocation[0], viewLocation[1]));
+ // The caption window may be a spy window when the caption background is
+ // transparent, which means events will fall through to the app window. Make
+ // sure to cancel these events if they do not happen in the intersection of the
+ // customizable region and what the app reported as exclusion areas, because
+ // the drag-move or other caption gestures should take priority outside those
+ // regions.
+ mShouldPilferCaptionEvents = !(downInCustomizableCaptionRegion
+ && downInExclusionRegion && isTransparentCaption) && !isResizeEvent;
+ }
+
+ if (!mShouldPilferCaptionEvents) {
+ // The event will be handled by a window below or pilfered by resize handler.
+ return false;
+ }
+ // Otherwise pilfer so that windows below receive cancellations for this gesture, and
+ // continue normal handling as a caption gesture.
+ if (mInputManager != null) {
+ // TODO(b/352127475): Only pilfer once per gesture
+ mInputManager.pilferPointers(v.getViewRootImpl().getInputToken());
+ }
+ if (isUpOrCancel) {
+ // Gesture is finished, reset state.
+ mShouldPilferCaptionEvents = false;
+ }
return mDragDetector.onMotionEvent(e);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
index d0ca5b0fdce6..7e1b973a98f4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
@@ -21,6 +21,7 @@ import static com.android.wm.shell.windowdecor.DragResizeWindowGeometry.getLarge
import static com.android.wm.shell.windowdecor.DragResizeWindowGeometry.getResizeEdgeHandleSize;
import android.annotation.NonNull;
+import android.app.ActivityManager;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.WindowConfiguration;
import android.app.WindowConfiguration.WindowingMode;
@@ -28,22 +29,27 @@ import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.graphics.Color;
+import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.VectorDrawable;
import android.os.Handler;
import android.util.Size;
import android.view.Choreographer;
+import android.view.MotionEvent;
import android.view.SurfaceControl;
import android.view.View;
import android.view.ViewConfiguration;
+import android.view.WindowManager;
import android.window.WindowContainerTransaction;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.wm.shell.R;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.SyncTransactionQueue;
+import com.android.wm.shell.windowdecor.extension.TaskInfoKt;
/**
* Defines visuals and behaviors of a window decoration of a caption bar and shadows. It works with
@@ -177,12 +183,44 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL
shouldSetTaskPositionAndCrop);
}
+ @VisibleForTesting
+ static void updateRelayoutParams(
+ RelayoutParams relayoutParams,
+ ActivityManager.RunningTaskInfo taskInfo,
+ boolean applyStartTransactionOnDraw,
+ boolean setTaskCropAndPosition) {
+ relayoutParams.reset();
+ relayoutParams.mRunningTaskInfo = taskInfo;
+ relayoutParams.mLayoutResId = R.layout.caption_window_decor;
+ relayoutParams.mCaptionHeightId = getCaptionHeightIdStatic(taskInfo.getWindowingMode());
+ relayoutParams.mShadowRadiusId = taskInfo.isFocused
+ ? R.dimen.freeform_decor_shadow_focused_thickness
+ : R.dimen.freeform_decor_shadow_unfocused_thickness;
+ relayoutParams.mApplyStartTransactionOnDraw = applyStartTransactionOnDraw;
+ relayoutParams.mSetTaskPositionAndCrop = setTaskCropAndPosition;
+
+ if (TaskInfoKt.isTransparentCaptionBarAppearance(taskInfo)) {
+ // If the app is requesting to customize the caption bar, allow input to fall
+ // through to the windows below so that the app can respond to input events on
+ // their custom content.
+ relayoutParams.mInputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_SPY;
+ }
+ final RelayoutParams.OccludingCaptionElement backButtonElement =
+ new RelayoutParams.OccludingCaptionElement();
+ backButtonElement.mWidthResId = R.dimen.caption_left_buttons_width;
+ backButtonElement.mAlignment = RelayoutParams.OccludingCaptionElement.Alignment.START;
+ relayoutParams.mOccludingCaptionElements.add(backButtonElement);
+ // Then, the right-aligned section (minimize, maximize and close buttons).
+ final RelayoutParams.OccludingCaptionElement controlsElement =
+ new RelayoutParams.OccludingCaptionElement();
+ controlsElement.mWidthResId = R.dimen.caption_right_buttons_width;
+ controlsElement.mAlignment = RelayoutParams.OccludingCaptionElement.Alignment.END;
+ relayoutParams.mOccludingCaptionElements.add(controlsElement);
+ }
+
void relayout(RunningTaskInfo taskInfo,
SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT,
boolean applyStartTransactionOnDraw, boolean setTaskCropAndPosition) {
- final int shadowRadiusID = taskInfo.isFocused
- ? R.dimen.freeform_decor_shadow_focused_thickness
- : R.dimen.freeform_decor_shadow_unfocused_thickness;
final boolean isFreeform =
taskInfo.getWindowingMode() == WindowConfiguration.WINDOWING_MODE_FREEFORM;
final boolean isDragResizeable = isFreeform && taskInfo.isResizeable;
@@ -191,13 +229,8 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL
final SurfaceControl oldDecorationSurface = mDecorationContainerSurface;
final WindowContainerTransaction wct = new WindowContainerTransaction();
- mRelayoutParams.reset();
- mRelayoutParams.mRunningTaskInfo = taskInfo;
- mRelayoutParams.mLayoutResId = R.layout.caption_window_decor;
- mRelayoutParams.mCaptionHeightId = getCaptionHeightId(taskInfo.getWindowingMode());
- mRelayoutParams.mShadowRadiusId = shadowRadiusID;
- mRelayoutParams.mApplyStartTransactionOnDraw = applyStartTransactionOnDraw;
- mRelayoutParams.mSetTaskPositionAndCrop = setTaskCropAndPosition;
+ updateRelayoutParams(mRelayoutParams, taskInfo, applyStartTransactionOnDraw,
+ setTaskCropAndPosition);
relayout(mRelayoutParams, startT, finishT, wct, oldRootView, mResult);
// After this line, mTaskInfo is up-to-date and should be used instead of taskInfo
@@ -303,6 +336,17 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL
mDragResizeListener = null;
}
+ /**
+ * Checks whether the touch event falls inside the customizable caption region.
+ */
+ boolean checkTouchEventInCustomizableRegion(MotionEvent ev) {
+ return mResult.mCustomizableCaptionRegion.contains((int) ev.getRawX(), (int) ev.getRawY());
+ }
+
+ boolean shouldResizeListenerHandleEvent(@NonNull MotionEvent e, @NonNull Point offset) {
+ return mDragResizeListener != null && mDragResizeListener.shouldHandleEvent(e, offset);
+ }
+
@Override
public void close() {
closeDragResizeListener();
@@ -311,6 +355,10 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL
@Override
int getCaptionHeightId(@WindowingMode int windowingMode) {
+ return getCaptionHeightIdStatic(windowingMode);
+ }
+
+ private static int getCaptionHeightIdStatic(@WindowingMode int windowingMode) {
return R.dimen.freeform_decor_caption_height;
}
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 faf6a627febe..d12b9060bee3 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
@@ -1040,7 +1040,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
private void createInputChannel(int displayId) {
final InputManager inputManager = mContext.getSystemService(InputManager.class);
final InputMonitor inputMonitor =
- mInputMonitorFactory.create(inputManager, mContext);
+ mInputMonitorFactory.create(inputManager, displayId);
final EventReceiver eventReceiver = new EventReceiver(inputMonitor,
inputMonitor.getInputChannel(), Looper.myLooper());
mEventReceiversByDisplay.put(displayId, eventReceiver);
@@ -1194,8 +1194,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
}
static class InputMonitorFactory {
- InputMonitor create(InputManager inputManager, Context context) {
- return inputManager.monitorGestureInput("caption-touch", context.getDisplayId());
+ InputMonitor create(InputManager inputManager, int displayId) {
+ return inputManager.monitorGestureInput("caption-touch", displayId);
}
}
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 5ffd883a7ceb..5d662b20ebb9 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
@@ -852,18 +852,19 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
*/
void createHandleMenu(SplitScreenController splitScreenController) {
loadAppInfoIfNeeded();
- mHandleMenu = new HandleMenu.Builder(this)
- .setAppIcon(mAppIconBitmap)
- .setAppName(mAppName)
- .setOnClickListener(mOnCaptionButtonClickListener)
- .setOnTouchListener(mOnCaptionTouchListener)
- .setLayoutId(mRelayoutParams.mLayoutResId)
- .setWindowingButtonsVisible(DesktopModeStatus.canEnterDesktopMode(mContext))
- .setCaptionHeight(mResult.mCaptionHeight)
- .setDisplayController(mDisplayController)
- .setSplitScreenController(splitScreenController)
- .setBrowserLinkAvailable(browserLinkAvailable())
- .build();
+ mHandleMenu = new HandleMenu(
+ this,
+ mRelayoutParams.mLayoutResId,
+ mOnCaptionButtonClickListener,
+ mOnCaptionTouchListener,
+ mAppIconBitmap,
+ mAppName,
+ mDisplayController,
+ splitScreenController,
+ DesktopModeStatus.canEnterDesktopMode(mContext),
+ browserLinkAvailable(),
+ mResult.mCaptionHeight
+ );
mWindowDecorViewHolder.onHandleMenuOpened();
mHandleMenu.show();
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
index a3616f65f3b2..32df8b3b2c7c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
@@ -468,8 +468,7 @@ class DragResizeInputListener implements AutoCloseable {
case MotionEvent.ACTION_HOVER_ENTER:
case MotionEvent.ACTION_HOVER_MOVE: {
updateCursorType(e.getDisplayId(), e.getDeviceId(),
- e.getPointerId(/*pointerIndex=*/0), e.getXCursorPosition(),
- e.getYCursorPosition());
+ e.getPointerId(/*pointerIndex=*/0), e.getX(), e.getY());
result = true;
break;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometry.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometry.java
index b5d1d4a76342..ba5f0791a010 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometry.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometry.java
@@ -33,9 +33,6 @@ import android.graphics.Region;
import android.util.Size;
import android.view.MotionEvent;
-import androidx.annotation.Nullable;
-import androidx.annotation.VisibleForTesting;
-
import com.android.wm.shell.R;
import java.util.Objects;
@@ -44,11 +41,6 @@ import java.util.Objects;
* Geometry for a drag resize region for a particular window.
*/
final class DragResizeWindowGeometry {
- // TODO(b/337264971) clean up when no longer needed
- @VisibleForTesting static final boolean DEBUG = true;
- // The additional width to apply to edge resize bounds just for logging when a touch is
- // close.
- @VisibleForTesting static final int EDGE_DEBUG_BUFFER = 15;
private final int mTaskCornerRadius;
private final Size mTaskSize;
// The size of the handle applied to the edges of the window, for the user to drag resize.
@@ -60,8 +52,6 @@ final class DragResizeWindowGeometry {
private final @NonNull TaskCorners mFineTaskCorners;
// The bounds for each edge drag region, which can resize the task in one direction.
private final @NonNull TaskEdges mTaskEdges;
- // Extra-large edge bounds for logging to help debug when an edge resize is ignored.
- private final @Nullable TaskEdges mDebugTaskEdges;
DragResizeWindowGeometry(int taskCornerRadius, @NonNull Size taskSize,
int resizeHandleThickness, int fineCornerSize, int largeCornerSize) {
@@ -74,11 +64,6 @@ final class DragResizeWindowGeometry {
// Save touch areas for each edge.
mTaskEdges = new TaskEdges(mTaskSize, mResizeHandleThickness);
- if (DEBUG) {
- mDebugTaskEdges = new TaskEdges(mTaskSize, mResizeHandleThickness + EDGE_DEBUG_BUFFER);
- } else {
- mDebugTaskEdges = null;
- }
}
/**
@@ -120,13 +105,7 @@ final class DragResizeWindowGeometry {
*/
void union(@NonNull Region region) {
// Apply the edge resize regions.
- if (inDebugMode()) {
- // Use the larger edge sizes if we are debugging, to be able to log if we ignored a
- // touch due to the size of the edge region.
- mDebugTaskEdges.union(region);
- } else {
- mTaskEdges.union(region);
- }
+ mTaskEdges.union(region);
if (enableWindowingEdgeDragResize()) {
// Apply the corners as well for the larger corners, to ensure we capture all possible
@@ -219,10 +198,6 @@ final class DragResizeWindowGeometry {
@DragPositioningCallback.CtrlType
private int calculateEdgeResizeCtrlType(float x, float y) {
- if (inDebugMode() && (mDebugTaskEdges.contains((int) x, (int) y)
- && !mTaskEdges.contains((int) x, (int) y))) {
- return CTRL_TYPE_UNDEFINED;
- }
int ctrlType = CTRL_TYPE_UNDEFINED;
// mTaskCornerRadius is only used in comparing with corner regions. Comparisons with
// sides will use the bounds specified in setGeometry and not go into task bounds.
@@ -313,9 +288,7 @@ final class DragResizeWindowGeometry {
&& this.mResizeHandleThickness == other.mResizeHandleThickness
&& this.mFineTaskCorners.equals(other.mFineTaskCorners)
&& this.mLargeTaskCorners.equals(other.mLargeTaskCorners)
- && (inDebugMode()
- ? this.mDebugTaskEdges.equals(other.mDebugTaskEdges)
- : this.mTaskEdges.equals(other.mTaskEdges));
+ && this.mTaskEdges.equals(other.mTaskEdges);
}
@Override
@@ -326,11 +299,7 @@ final class DragResizeWindowGeometry {
mResizeHandleThickness,
mFineTaskCorners,
mLargeTaskCorners,
- (inDebugMode() ? mDebugTaskEdges : mTaskEdges));
- }
-
- private boolean inDebugMode() {
- return DEBUG && mDebugTaskEdges != null;
+ mTaskEdges);
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.java
deleted file mode 100644
index 7e44f32bcbeb..000000000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.java
+++ /dev/null
@@ -1,539 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.windowdecor;
-
-import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
-import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
-import static android.view.MotionEvent.ACTION_DOWN;
-import static android.view.MotionEvent.ACTION_UP;
-
-import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.ActivityManager.RunningTaskInfo;
-import android.content.Context;
-import android.content.res.ColorStateList;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.graphics.Bitmap;
-import android.graphics.Color;
-import android.graphics.Point;
-import android.graphics.PointF;
-import android.graphics.Rect;
-import android.view.MotionEvent;
-import android.view.SurfaceControl;
-import android.view.View;
-import android.widget.Button;
-import android.widget.ImageButton;
-import android.widget.ImageView;
-import android.widget.TextView;
-import android.window.SurfaceSyncGroup;
-
-import androidx.annotation.VisibleForTesting;
-
-import com.android.window.flags.Flags;
-import com.android.wm.shell.R;
-import com.android.wm.shell.common.DisplayController;
-import com.android.wm.shell.common.DisplayLayout;
-import com.android.wm.shell.splitscreen.SplitScreenController;
-import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalSystemViewContainer;
-import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalViewContainer;
-
-/**
- * Handle menu opened when the appropriate button is clicked on.
- *
- * Displays up to 3 pills that show the following:
- * App Info: App name, app icon, and collapse button to close the menu.
- * Windowing Options(Proto 2 only): Buttons to change windowing modes.
- * Additional Options: Miscellaneous functions including screenshot and closing task.
- */
-class HandleMenu {
- private static final String TAG = "HandleMenu";
- private static final boolean SHOULD_SHOW_MORE_ACTIONS_PILL = false;
- private final Context mContext;
- private final DesktopModeWindowDecoration mParentDecor;
- @VisibleForTesting
- AdditionalViewContainer mHandleMenuViewContainer;
- // Position of the handle menu used for laying out the handle view.
- @VisibleForTesting
- final PointF mHandleMenuPosition = new PointF();
- // With the introduction of {@link AdditionalSystemViewContainer}, {@link mHandleMenuPosition}
- // may be in a different coordinate space than the input coordinates. Therefore, we still care
- // about the menu's coordinates relative to the display as a whole, so we need to maintain
- // those as well.
- final Point mGlobalMenuPosition = new Point();
- private final boolean mShouldShowWindowingPill;
- private final boolean mShouldShowBrowserPill;
- private final Bitmap mAppIconBitmap;
- private final CharSequence mAppName;
- private final View.OnClickListener mOnClickListener;
- private final View.OnTouchListener mOnTouchListener;
- private final RunningTaskInfo mTaskInfo;
- private final DisplayController mDisplayController;
- private final SplitScreenController mSplitScreenController;
- private final int mLayoutResId;
- private int mMarginMenuTop;
- private int mMarginMenuStart;
- private int mMenuHeight;
- private int mMenuWidth;
- private final int mCaptionHeight;
- private HandleMenuAnimator mHandleMenuAnimator;
-
-
- HandleMenu(DesktopModeWindowDecoration parentDecor, int layoutResId,
- View.OnClickListener onClickListener, View.OnTouchListener onTouchListener,
- Bitmap appIcon, CharSequence appName, DisplayController displayController,
- SplitScreenController splitScreenController, boolean shouldShowWindowingPill,
- boolean shouldShowBrowserPill, int captionHeight) {
- mParentDecor = parentDecor;
- mContext = mParentDecor.mDecorWindowContext;
- mTaskInfo = mParentDecor.mTaskInfo;
- mDisplayController = displayController;
- mSplitScreenController = splitScreenController;
- mLayoutResId = layoutResId;
- mOnClickListener = onClickListener;
- mOnTouchListener = onTouchListener;
- mAppIconBitmap = appIcon;
- mAppName = appName;
- mShouldShowWindowingPill = shouldShowWindowingPill;
- mShouldShowBrowserPill = shouldShowBrowserPill;
- mCaptionHeight = captionHeight;
- loadHandleMenuDimensions();
- updateHandleMenuPillPositions();
- }
-
- void show() {
- final SurfaceSyncGroup ssg = new SurfaceSyncGroup(TAG);
- SurfaceControl.Transaction t = new SurfaceControl.Transaction();
-
- createHandleMenuViewContainer(t, ssg);
- ssg.addTransaction(t);
- ssg.markSyncReady();
- setupHandleMenu();
- animateHandleMenu();
- }
-
- private void createHandleMenuViewContainer(SurfaceControl.Transaction t,
- SurfaceSyncGroup ssg) {
- final int x = (int) mHandleMenuPosition.x;
- final int y = (int) mHandleMenuPosition.y;
- if (!mTaskInfo.isFreeform() && Flags.enableAdditionalWindowsAboveStatusBar()) {
- mHandleMenuViewContainer = new AdditionalSystemViewContainer(mContext,
- R.layout.desktop_mode_window_decor_handle_menu, mTaskInfo.taskId,
- x, y, mMenuWidth, mMenuHeight);
- } else {
- mHandleMenuViewContainer = mParentDecor.addWindow(
- R.layout.desktop_mode_window_decor_handle_menu, "Handle Menu",
- t, ssg, x, y, mMenuWidth, mMenuHeight);
- }
- final View handleMenuView = mHandleMenuViewContainer.getView();
- mHandleMenuAnimator = new HandleMenuAnimator(handleMenuView, mMenuWidth, mCaptionHeight);
- }
-
- /**
- * Animates the appearance of the handle menu and its three pills.
- */
- private void animateHandleMenu() {
- if (mTaskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN
- || mTaskInfo.getWindowingMode() == WINDOWING_MODE_MULTI_WINDOW) {
- mHandleMenuAnimator.animateCaptionHandleExpandToOpen();
- } else {
- mHandleMenuAnimator.animateOpen();
- }
- }
-
- /**
- * Set up all three pills of the handle menu: app info pill, windowing pill, & more actions
- * pill.
- */
- private void setupHandleMenu() {
- final View handleMenu = mHandleMenuViewContainer.getView();
- handleMenu.setOnTouchListener(mOnTouchListener);
- setupAppInfoPill(handleMenu);
- if (mShouldShowWindowingPill) {
- setupWindowingPill(handleMenu);
- }
- setupMoreActionsPill(handleMenu);
- setupOpenInBrowserPill(handleMenu);
- }
-
- /**
- * Set up interactive elements of handle menu's app info pill.
- */
- private void setupAppInfoPill(View handleMenu) {
- final HandleMenuImageButton collapseBtn =
- handleMenu.findViewById(R.id.collapse_menu_button);
- final ImageView appIcon = handleMenu.findViewById(R.id.application_icon);
- final TextView appName = handleMenu.findViewById(R.id.application_name);
- collapseBtn.setOnClickListener(mOnClickListener);
- collapseBtn.setTaskInfo(mTaskInfo);
- appIcon.setImageBitmap(mAppIconBitmap);
- appName.setText(mAppName);
- }
-
- /**
- * Set up interactive elements and color of handle menu's windowing pill.
- */
- private void setupWindowingPill(View handleMenu) {
- final ImageButton fullscreenBtn = handleMenu.findViewById(
- R.id.fullscreen_button);
- final ImageButton splitscreenBtn = handleMenu.findViewById(
- R.id.split_screen_button);
- final ImageButton floatingBtn = handleMenu.findViewById(R.id.floating_button);
- // TODO: Remove once implemented.
- floatingBtn.setVisibility(View.GONE);
-
- final ImageButton desktopBtn = handleMenu.findViewById(R.id.desktop_button);
- fullscreenBtn.setOnClickListener(mOnClickListener);
- splitscreenBtn.setOnClickListener(mOnClickListener);
- floatingBtn.setOnClickListener(mOnClickListener);
- desktopBtn.setOnClickListener(mOnClickListener);
- // The button corresponding to the windowing mode that the task is currently in uses a
- // different color than the others.
- final ColorStateList[] iconColors = getWindowingIconColor();
- final ColorStateList inActiveColorStateList = iconColors[0];
- final ColorStateList activeColorStateList = iconColors[1];
- final int windowingMode = mTaskInfo.getWindowingMode();
- fullscreenBtn.setImageTintList(windowingMode == WINDOWING_MODE_FULLSCREEN
- ? activeColorStateList : inActiveColorStateList);
- splitscreenBtn.setImageTintList(windowingMode == WINDOWING_MODE_MULTI_WINDOW
- ? activeColorStateList : inActiveColorStateList);
- floatingBtn.setImageTintList(windowingMode == WINDOWING_MODE_PINNED
- ? activeColorStateList : inActiveColorStateList);
- desktopBtn.setImageTintList(windowingMode == WINDOWING_MODE_FREEFORM
- ? activeColorStateList : inActiveColorStateList);
- }
-
- /**
- * Set up interactive elements & height of handle menu's more actions pill
- */
- private void setupMoreActionsPill(View handleMenu) {
- if (!SHOULD_SHOW_MORE_ACTIONS_PILL) {
- handleMenu.findViewById(R.id.more_actions_pill).setVisibility(View.GONE);
- }
- }
-
- private void setupOpenInBrowserPill(View handleMenu) {
- if (!mShouldShowBrowserPill) {
- handleMenu.findViewById(R.id.open_in_browser_pill).setVisibility(View.GONE);
- return;
- }
- final Button browserButton = handleMenu.findViewById(R.id.open_in_browser_button);
- browserButton.setOnClickListener(mOnClickListener);
- }
-
- /**
- * Returns array of windowing icon color based on current UI theme. First element of the
- * array is for inactive icons and the second is for active icons.
- */
- private ColorStateList[] getWindowingIconColor() {
- final int mode = mContext.getResources().getConfiguration().uiMode
- & Configuration.UI_MODE_NIGHT_MASK;
- final boolean isNightMode = (mode == Configuration.UI_MODE_NIGHT_YES);
- final TypedArray typedArray = mContext.obtainStyledAttributes(new int[]{
- com.android.internal.R.attr.materialColorOnSurface,
- com.android.internal.R.attr.materialColorPrimary});
- final int inActiveColor = typedArray.getColor(0, isNightMode ? Color.WHITE : Color.BLACK);
- final int activeColor = typedArray.getColor(1, isNightMode ? Color.WHITE : Color.BLACK);
- typedArray.recycle();
- return new ColorStateList[]{ColorStateList.valueOf(inActiveColor),
- ColorStateList.valueOf(activeColor)};
- }
-
- /**
- * Updates handle menu's position variables to reflect its next position.
- */
- private void updateHandleMenuPillPositions() {
- int menuX;
- final int menuY;
- final Rect taskBounds = mTaskInfo.getConfiguration().windowConfiguration.getBounds();
- updateGlobalMenuPosition(taskBounds);
- if (mLayoutResId == R.layout.desktop_mode_app_header) {
- // Align the handle menu to the left side of the caption.
- menuX = mMarginMenuStart;
- menuY = mMarginMenuTop;
- } else {
- if (Flags.enableAdditionalWindowsAboveStatusBar()) {
- // In a focused decor, we use global coordinates for handle menu. Therefore we
- // need to account for other factors like split stage and menu/handle width to
- // center the menu.
- final DisplayLayout layout = mDisplayController
- .getDisplayLayout(mTaskInfo.displayId);
- menuX = mGlobalMenuPosition.x + ((mMenuWidth - layout.width()) / 2);
- menuY = mGlobalMenuPosition.y + ((mMenuHeight - layout.height()) / 2);
- } else {
- menuX = (taskBounds.width() / 2) - (mMenuWidth / 2);
- menuY = mMarginMenuTop;
- }
- }
- // Handle Menu position setup.
- mHandleMenuPosition.set(menuX, menuY);
- }
-
- private void updateGlobalMenuPosition(Rect taskBounds) {
- if (mTaskInfo.isFreeform()) {
- mGlobalMenuPosition.set(taskBounds.left + mMarginMenuStart,
- taskBounds.top + mMarginMenuTop);
- } else if (mTaskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) {
- mGlobalMenuPosition.set(
- (taskBounds.width() / 2) - (mMenuWidth / 2) + mMarginMenuStart,
- mMarginMenuTop
- );
- } else if (mTaskInfo.getWindowingMode() == WINDOWING_MODE_MULTI_WINDOW) {
- final int splitPosition = mSplitScreenController.getSplitPosition(mTaskInfo.taskId);
- final Rect leftOrTopStageBounds = new Rect();
- final Rect rightOrBottomStageBounds = new Rect();
- mSplitScreenController.getStageBounds(leftOrTopStageBounds,
- rightOrBottomStageBounds);
- // TODO(b/343561161): This needs to be calculated differently if the task is in
- // top/bottom split.
- if (splitPosition == SPLIT_POSITION_BOTTOM_OR_RIGHT) {
- mGlobalMenuPosition.set(leftOrTopStageBounds.width()
- + (rightOrBottomStageBounds.width() / 2)
- - (mMenuWidth / 2) + mMarginMenuStart,
- mMarginMenuTop);
- } else if (splitPosition == SPLIT_POSITION_TOP_OR_LEFT) {
- mGlobalMenuPosition.set((leftOrTopStageBounds.width() / 2)
- - (mMenuWidth / 2) + mMarginMenuStart,
- mMarginMenuTop);
- }
- }
- }
-
- /**
- * Update pill layout, in case task changes have caused positioning to change.
- */
- void relayout(SurfaceControl.Transaction t) {
- if (mHandleMenuViewContainer != null) {
- updateHandleMenuPillPositions();
- mHandleMenuViewContainer.setPosition(t, mHandleMenuPosition.x, mHandleMenuPosition.y);
- }
- }
-
- /**
- * Check a passed MotionEvent if a click or hover has occurred on any button on this caption
- * Note this should only be called when a regular onClick/onHover is not possible
- * (i.e. the button was clicked through status bar layer)
- *
- * @param ev the MotionEvent to compare against.
- */
- void checkMotionEvent(MotionEvent ev) {
- // If the menu view is above status bar, we can let the views handle input directly.
- if (isViewAboveStatusBar()) return;
- final View handleMenu = mHandleMenuViewContainer.getView();
- final HandleMenuImageButton collapse = handleMenu.findViewById(R.id.collapse_menu_button);
- final PointF inputPoint = translateInputToLocalSpace(ev);
- final boolean inputInCollapseButton = pointInView(collapse, inputPoint.x, inputPoint.y);
- final int action = ev.getActionMasked();
- collapse.setHovered(inputInCollapseButton && action != ACTION_UP);
- collapse.setPressed(inputInCollapseButton && action == ACTION_DOWN);
- if (action == ACTION_UP && inputInCollapseButton) {
- collapse.performClick();
- }
- }
-
- private boolean isViewAboveStatusBar() {
- return Flags.enableAdditionalWindowsAboveStatusBar()
- && !mTaskInfo.isFreeform();
- }
-
- // Translate the input point from display coordinates to the same space as the handle menu.
- private PointF translateInputToLocalSpace(MotionEvent ev) {
- return new PointF(ev.getX() - mHandleMenuPosition.x,
- ev.getY() - mHandleMenuPosition.y);
- }
-
- /**
- * A valid menu input is one of the following:
- * An input that happens in the menu views.
- * Any input before the views have been laid out.
- *
- * @param inputPoint the input to compare against.
- */
- boolean isValidMenuInput(PointF inputPoint) {
- if (!viewsLaidOut()) return true;
- if (!isViewAboveStatusBar()) {
- return pointInView(
- mHandleMenuViewContainer.getView(),
- inputPoint.x - mHandleMenuPosition.x,
- inputPoint.y - mHandleMenuPosition.y);
- } else {
- // Handle menu exists in a different coordinate space when added to WindowManager.
- // Therefore we must compare the provided input coordinates to global menu coordinates.
- // This includes factoring for split stage as input coordinates are relative to split
- // stage position, not relative to the display as a whole.
- PointF inputRelativeToMenu = new PointF(
- inputPoint.x - mGlobalMenuPosition.x,
- inputPoint.y - mGlobalMenuPosition.y
- );
- if (mSplitScreenController.getSplitPosition(mTaskInfo.taskId)
- == SPLIT_POSITION_BOTTOM_OR_RIGHT) {
- // TODO(b/343561161): This also needs to be calculated differently if
- // the task is in top/bottom split.
- Rect leftStageBounds = new Rect();
- mSplitScreenController.getStageBounds(leftStageBounds, new Rect());
- inputRelativeToMenu.x += leftStageBounds.width();
- }
- return pointInView(
- mHandleMenuViewContainer.getView(),
- inputRelativeToMenu.x,
- inputRelativeToMenu.y);
- }
- }
-
- private boolean pointInView(View v, float x, float y) {
- return v != null && v.getLeft() <= x && v.getRight() >= x
- && v.getTop() <= y && v.getBottom() >= y;
- }
-
- /**
- * Check if the views for handle menu can be seen.
- */
- private boolean viewsLaidOut() {
- return mHandleMenuViewContainer.getView().isLaidOut();
- }
-
- private void loadHandleMenuDimensions() {
- final Resources resources = mContext.getResources();
- mMenuWidth = loadDimensionPixelSize(resources,
- R.dimen.desktop_mode_handle_menu_width);
- mMenuHeight = getHandleMenuHeight(resources);
- mMarginMenuTop = loadDimensionPixelSize(resources,
- R.dimen.desktop_mode_handle_menu_margin_top);
- mMarginMenuStart = loadDimensionPixelSize(resources,
- R.dimen.desktop_mode_handle_menu_margin_start);
- }
-
- /**
- * Determines handle menu height based on if windowing pill should be shown.
- */
- private int getHandleMenuHeight(Resources resources) {
- int menuHeight = loadDimensionPixelSize(resources, R.dimen.desktop_mode_handle_menu_height);
- if (!mShouldShowWindowingPill) {
- menuHeight -= loadDimensionPixelSize(resources,
- R.dimen.desktop_mode_handle_menu_windowing_pill_height);
- }
- if (!SHOULD_SHOW_MORE_ACTIONS_PILL) {
- menuHeight -= loadDimensionPixelSize(resources,
- R.dimen.desktop_mode_handle_menu_more_actions_pill_height);
- }
- if (!mShouldShowBrowserPill) {
- menuHeight -= loadDimensionPixelSize(resources,
- R.dimen.desktop_mode_handle_menu_open_in_browser_pill_height);
- }
- return menuHeight;
- }
-
- private int loadDimensionPixelSize(Resources resources, int resourceId) {
- if (resourceId == Resources.ID_NULL) {
- return 0;
- }
- return resources.getDimensionPixelSize(resourceId);
- }
-
- void close() {
- final Runnable after = () -> {
- mHandleMenuViewContainer.releaseView();
- mHandleMenuViewContainer = null;
- };
- if (mTaskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN
- || mTaskInfo.getWindowingMode() == WINDOWING_MODE_MULTI_WINDOW) {
- mHandleMenuAnimator.animateCollapseIntoHandleClose(after);
- } else {
- mHandleMenuAnimator.animateClose(after);
- }
- }
-
- static final class Builder {
- private final DesktopModeWindowDecoration mParent;
- private CharSequence mName;
- private Bitmap mAppIcon;
- private View.OnClickListener mOnClickListener;
- private View.OnTouchListener mOnTouchListener;
- private int mLayoutId;
- private boolean mShowWindowingPill;
- private int mCaptionHeight;
- private DisplayController mDisplayController;
- private SplitScreenController mSplitScreenController;
- private boolean mShowBrowserPill;
-
- Builder(@NonNull DesktopModeWindowDecoration parent) {
- mParent = parent;
- }
-
- Builder setAppName(@Nullable CharSequence name) {
- mName = name;
- return this;
- }
-
- Builder setAppIcon(@Nullable Bitmap appIcon) {
- mAppIcon = appIcon;
- return this;
- }
-
- Builder setOnClickListener(@Nullable View.OnClickListener onClickListener) {
- mOnClickListener = onClickListener;
- return this;
- }
-
- Builder setOnTouchListener(@Nullable View.OnTouchListener onTouchListener) {
- mOnTouchListener = onTouchListener;
- return this;
- }
-
- Builder setLayoutId(int layoutId) {
- mLayoutId = layoutId;
- return this;
- }
-
- Builder setWindowingButtonsVisible(boolean windowingButtonsVisible) {
- mShowWindowingPill = windowingButtonsVisible;
- return this;
- }
-
- Builder setCaptionHeight(int captionHeight) {
- mCaptionHeight = captionHeight;
- return this;
- }
-
- Builder setDisplayController(DisplayController displayController) {
- mDisplayController = displayController;
- return this;
- }
-
- Builder setSplitScreenController(SplitScreenController splitScreenController) {
- mSplitScreenController = splitScreenController;
- return this;
- }
-
- Builder setBrowserLinkAvailable(Boolean showBrowserPill) {
- mShowBrowserPill = showBrowserPill;
- return this;
- }
-
- HandleMenu build() {
- return new HandleMenu(mParent, mLayoutId, mOnClickListener,
- mOnTouchListener, mAppIcon, mName, mDisplayController, mSplitScreenController,
- mShowWindowingPill, mShowBrowserPill, mCaptionHeight);
- }
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt
new file mode 100644
index 000000000000..bce233fb0b52
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt
@@ -0,0 +1,484 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.wm.shell.windowdecor
+
+import android.annotation.DimenRes
+import android.app.ActivityManager
+import android.app.WindowConfiguration
+import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM
+import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN
+import android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW
+import android.app.WindowConfiguration.WINDOWING_MODE_PINNED
+import android.content.Context
+import android.content.res.ColorStateList
+import android.content.res.Configuration
+import android.content.res.Resources
+import android.graphics.Bitmap
+import android.graphics.Color
+import android.graphics.Point
+import android.graphics.PointF
+import android.graphics.Rect
+import android.view.MotionEvent
+import android.view.SurfaceControl
+import android.view.View
+import android.widget.Button
+import android.widget.ImageButton
+import android.widget.ImageView
+import android.widget.TextView
+import android.window.SurfaceSyncGroup
+import androidx.annotation.VisibleForTesting
+import com.android.window.flags.Flags
+import com.android.wm.shell.R
+import com.android.wm.shell.common.DisplayController
+import com.android.wm.shell.common.split.SplitScreenConstants
+import com.android.wm.shell.splitscreen.SplitScreenController
+import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalSystemViewContainer
+import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalViewContainer
+import com.android.wm.shell.windowdecor.extension.isFullscreen
+
+/**
+ * Handle menu opened when the appropriate button is clicked on.
+ *
+ * Displays up to 3 pills that show the following:
+ * App Info: App name, app icon, and collapse button to close the menu.
+ * Windowing Options(Proto 2 only): Buttons to change windowing modes.
+ * Additional Options: Miscellaneous functions including screenshot and closing task.
+ */
+class HandleMenu(
+ private val parentDecor: DesktopModeWindowDecoration,
+ private val layoutResId: Int,
+ private val onClickListener: View.OnClickListener?,
+ private val onTouchListener: View.OnTouchListener?,
+ private val appIconBitmap: Bitmap?,
+ private val appName: CharSequence?,
+ private val displayController: DisplayController,
+ private val splitScreenController: SplitScreenController,
+ private val shouldShowWindowingPill: Boolean,
+ private val shouldShowBrowserPill: Boolean,
+ private val captionHeight: Int
+) {
+ private val context: Context = parentDecor.mDecorWindowContext
+ private val taskInfo: ActivityManager.RunningTaskInfo = parentDecor.mTaskInfo
+
+ private val isViewAboveStatusBar: Boolean
+ get() = (Flags.enableAdditionalWindowsAboveStatusBar() && !taskInfo.isFreeform)
+
+ private val pillElevation: Int = loadDimensionPixelSize(
+ R.dimen.desktop_mode_handle_menu_pill_elevation)
+ private val pillTopMargin: Int = loadDimensionPixelSize(
+ R.dimen.desktop_mode_handle_menu_pill_spacing_margin)
+ private val menuWidth = loadDimensionPixelSize(
+ R.dimen.desktop_mode_handle_menu_width) + pillElevation
+ private val menuHeight = getHandleMenuHeight()
+ private val marginMenuTop = loadDimensionPixelSize(R.dimen.desktop_mode_handle_menu_margin_top)
+ private val marginMenuStart = loadDimensionPixelSize(
+ R.dimen.desktop_mode_handle_menu_margin_start)
+
+ private var handleMenuAnimator: HandleMenuAnimator? = null
+
+ @VisibleForTesting
+ var handleMenuViewContainer: AdditionalViewContainer? = null
+
+ // Position of the handle menu used for laying out the handle view.
+ @VisibleForTesting
+ val handleMenuPosition: PointF = PointF()
+
+ // With the introduction of {@link AdditionalSystemViewContainer}, {@link mHandleMenuPosition}
+ // may be in a different coordinate space than the input coordinates. Therefore, we still care
+ // about the menu's coordinates relative to the display as a whole, so we need to maintain
+ // those as well.
+ private val globalMenuPosition: Point = Point()
+
+ /**
+ * An a array of windowing icon color based on current UI theme. First element of the
+ * array is for inactive icons and the second is for active icons.
+ */
+ private val windowingIconColor: Array<ColorStateList>
+ get() {
+ val mode = (context.resources.configuration.uiMode
+ and Configuration.UI_MODE_NIGHT_MASK)
+ val isNightMode = (mode == Configuration.UI_MODE_NIGHT_YES)
+ val typedArray = context.obtainStyledAttributes(
+ intArrayOf(
+ com.android.internal.R.attr.materialColorOnSurface,
+ com.android.internal.R.attr.materialColorPrimary
+ )
+ )
+ val inActiveColor =
+ typedArray.getColor(0, if (isNightMode) Color.WHITE else Color.BLACK)
+ val activeColor = typedArray.getColor(1, if (isNightMode) Color.WHITE else Color.BLACK)
+ typedArray.recycle()
+ return arrayOf(
+ ColorStateList.valueOf(inActiveColor),
+ ColorStateList.valueOf(activeColor)
+ )
+ }
+
+ init {
+ updateHandleMenuPillPositions()
+ }
+
+ fun show() {
+ val ssg = SurfaceSyncGroup(TAG)
+ val t = SurfaceControl.Transaction()
+
+ createHandleMenuViewContainer(t, ssg)
+ ssg.addTransaction(t)
+ ssg.markSyncReady()
+ setupHandleMenu()
+ animateHandleMenu()
+ }
+
+ private fun createHandleMenuViewContainer(
+ t: SurfaceControl.Transaction,
+ ssg: SurfaceSyncGroup
+ ) {
+ val x = handleMenuPosition.x.toInt()
+ val y = handleMenuPosition.y.toInt()
+ handleMenuViewContainer =
+ if (!taskInfo.isFreeform && Flags.enableAdditionalWindowsAboveStatusBar()) {
+ AdditionalSystemViewContainer(
+ context = context,
+ layoutId = R.layout.desktop_mode_window_decor_handle_menu,
+ taskId = taskInfo.taskId,
+ x = x,
+ y = y,
+ width = menuWidth,
+ height = menuHeight
+ )
+ } else {
+ parentDecor.addWindow(
+ R.layout.desktop_mode_window_decor_handle_menu, "Handle Menu",
+ t, ssg, x, y, menuWidth, menuHeight
+ )
+ }
+ handleMenuViewContainer?.view?.let { view ->
+ handleMenuAnimator =
+ HandleMenuAnimator(view, menuWidth, captionHeight.toFloat())
+ }
+ }
+
+ /**
+ * Animates the appearance of the handle menu and its three pills.
+ */
+ private fun animateHandleMenu() {
+ when (taskInfo.windowingMode) {
+ WindowConfiguration.WINDOWING_MODE_FULLSCREEN,
+ WINDOWING_MODE_MULTI_WINDOW -> {
+ handleMenuAnimator?.animateCaptionHandleExpandToOpen()
+ }
+ else -> {
+ handleMenuAnimator?.animateOpen()
+ }
+ }
+ }
+
+ /**
+ * Set up all three pills of the handle menu: app info pill, windowing pill, & more actions
+ * pill.
+ */
+ private fun setupHandleMenu() {
+ val handleMenu = handleMenuViewContainer?.view ?: return
+ handleMenu.setOnTouchListener(onTouchListener)
+ setupAppInfoPill(handleMenu)
+ if (shouldShowWindowingPill) {
+ setupWindowingPill(handleMenu)
+ }
+ setupMoreActionsPill(handleMenu)
+ setupOpenInBrowserPill(handleMenu)
+ }
+
+ /**
+ * Set up interactive elements of handle menu's app info pill.
+ */
+ private fun setupAppInfoPill(handleMenu: View) {
+ val collapseBtn = handleMenu.findViewById<HandleMenuImageButton>(R.id.collapse_menu_button)
+ val appIcon = handleMenu.findViewById<ImageView>(R.id.application_icon)
+ val appName = handleMenu.findViewById<TextView>(R.id.application_name)
+ collapseBtn.setOnClickListener(onClickListener)
+ collapseBtn.taskInfo = taskInfo
+ appIcon.setImageBitmap(appIconBitmap)
+ appName.text = this.appName
+ }
+
+ /**
+ * Set up interactive elements and color of handle menu's windowing pill.
+ */
+ private fun setupWindowingPill(handleMenu: View) {
+ val fullscreenBtn = handleMenu.findViewById<ImageButton>(R.id.fullscreen_button)
+ val splitscreenBtn = handleMenu.findViewById<ImageButton>(R.id.split_screen_button)
+ val floatingBtn = handleMenu.findViewById<ImageButton>(R.id.floating_button)
+ // TODO: Remove once implemented.
+ floatingBtn.visibility = View.GONE
+
+ val desktopBtn = handleMenu.findViewById<ImageButton>(R.id.desktop_button)
+ fullscreenBtn.setOnClickListener(onClickListener)
+ splitscreenBtn.setOnClickListener(onClickListener)
+ floatingBtn.setOnClickListener(onClickListener)
+ desktopBtn.setOnClickListener(onClickListener)
+ // The button corresponding to the windowing mode that the task is currently in uses a
+ // different color than the others.
+ val iconColors = windowingIconColor
+ val inActiveColorStateList = iconColors[0]
+ val activeColorStateList = iconColors[1]
+ fullscreenBtn.imageTintList = if (taskInfo.isFullscreen) {
+ activeColorStateList
+ } else {
+ inActiveColorStateList
+ }
+ splitscreenBtn.imageTintList = if (taskInfo.windowingMode == WINDOWING_MODE_MULTI_WINDOW) {
+ activeColorStateList
+ } else {
+ inActiveColorStateList
+ }
+ floatingBtn.imageTintList = if (taskInfo.windowingMode == WINDOWING_MODE_PINNED) {
+ activeColorStateList
+ } else {
+ inActiveColorStateList
+ }
+ desktopBtn.imageTintList = if (taskInfo.isFreeform) {
+ activeColorStateList
+ } else {
+ inActiveColorStateList
+ }
+ }
+
+ /**
+ * Set up interactive elements & height of handle menu's more actions pill
+ */
+ private fun setupMoreActionsPill(handleMenu: View) {
+ if (!SHOULD_SHOW_MORE_ACTIONS_PILL) {
+ handleMenu.findViewById<View>(R.id.more_actions_pill).visibility = View.GONE
+ }
+ }
+
+ private fun setupOpenInBrowserPill(handleMenu: View) {
+ if (!shouldShowBrowserPill) {
+ handleMenu.findViewById<View>(R.id.open_in_browser_pill).visibility = View.GONE
+ return
+ }
+ val browserButton = handleMenu.findViewById<Button>(R.id.open_in_browser_button)
+ browserButton.setOnClickListener(onClickListener)
+ }
+
+ /**
+ * Updates handle menu's position variables to reflect its next position.
+ */
+ private fun updateHandleMenuPillPositions() {
+ val menuX: Int
+ val menuY: Int
+ val taskBounds = taskInfo.getConfiguration().windowConfiguration.bounds
+ updateGlobalMenuPosition(taskBounds)
+ if (layoutResId == R.layout.desktop_mode_app_header) {
+ // Align the handle menu to the left side of the caption.
+ menuX = marginMenuStart
+ menuY = marginMenuTop
+ } else {
+ if (Flags.enableAdditionalWindowsAboveStatusBar()) {
+ // In a focused decor, we use global coordinates for handle menu. Therefore we
+ // need to account for other factors like split stage and menu/handle width to
+ // center the menu.
+ menuX = globalMenuPosition.x
+ menuY = globalMenuPosition.y
+ } else {
+ menuX = (taskBounds.width() / 2) - (menuWidth / 2)
+ menuY = marginMenuTop
+ }
+ }
+ // Handle Menu position setup.
+ handleMenuPosition.set(menuX.toFloat(), menuY.toFloat())
+ }
+
+ private fun updateGlobalMenuPosition(taskBounds: Rect) {
+ when (taskInfo.windowingMode) {
+ WINDOWING_MODE_FREEFORM -> {
+ globalMenuPosition.set(
+ /* x = */ taskBounds.left + marginMenuStart,
+ /* y = */ taskBounds.top + marginMenuTop
+ )
+ }
+ WINDOWING_MODE_FULLSCREEN -> {
+ globalMenuPosition.set(
+ /* x = */ taskBounds.width() / 2 - (menuWidth / 2),
+ /* y = */ marginMenuTop
+ )
+ }
+ WINDOWING_MODE_MULTI_WINDOW -> {
+ val splitPosition = splitScreenController.getSplitPosition(taskInfo.taskId)
+ val leftOrTopStageBounds = Rect()
+ val rightOrBottomStageBounds = Rect()
+ splitScreenController.getStageBounds(leftOrTopStageBounds, rightOrBottomStageBounds)
+ // TODO(b/343561161): This needs to be calculated differently if the task is in
+ // top/bottom split.
+ when (splitPosition) {
+ SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT -> {
+ globalMenuPosition.set(
+ /* x = */ leftOrTopStageBounds.width()
+ + (rightOrBottomStageBounds.width() / 2)
+ - (menuWidth / 2),
+ /* y = */ marginMenuTop
+ )
+ }
+ SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT -> {
+ globalMenuPosition.set(
+ /* x = */ (leftOrTopStageBounds.width() / 2)
+ - (menuWidth / 2),
+ /* y = */ marginMenuTop
+ )
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Update pill layout, in case task changes have caused positioning to change.
+ */
+ fun relayout(t: SurfaceControl.Transaction) {
+ handleMenuViewContainer?.let { container ->
+ updateHandleMenuPillPositions()
+ container.setPosition(t, handleMenuPosition.x, handleMenuPosition.y)
+ }
+ }
+
+ /**
+ * Check a passed MotionEvent if a click or hover has occurred on any button on this caption
+ * Note this should only be called when a regular onClick/onHover is not possible
+ * (i.e. the button was clicked through status bar layer)
+ *
+ * @param ev the MotionEvent to compare against.
+ */
+ fun checkMotionEvent(ev: MotionEvent) {
+ // If the menu view is above status bar, we can let the views handle input directly.
+ if (isViewAboveStatusBar) return
+ val handleMenu = handleMenuViewContainer?.view ?: return
+ val collapse = handleMenu.findViewById<HandleMenuImageButton>(R.id.collapse_menu_button)
+ val inputPoint = translateInputToLocalSpace(ev)
+ val inputInCollapseButton = pointInView(collapse, inputPoint.x, inputPoint.y)
+ val action = ev.actionMasked
+ collapse.isHovered = inputInCollapseButton && action != MotionEvent.ACTION_UP
+ collapse.isPressed = inputInCollapseButton && action == MotionEvent.ACTION_DOWN
+ if (action == MotionEvent.ACTION_UP && inputInCollapseButton) {
+ collapse.performClick()
+ }
+ }
+
+ // Translate the input point from display coordinates to the same space as the handle menu.
+ private fun translateInputToLocalSpace(ev: MotionEvent): PointF {
+ return PointF(
+ ev.x - handleMenuPosition.x,
+ ev.y - handleMenuPosition.y
+ )
+ }
+
+ /**
+ * A valid menu input is one of the following:
+ * An input that happens in the menu views.
+ * Any input before the views have been laid out.
+ *
+ * @param inputPoint the input to compare against.
+ */
+ fun isValidMenuInput(inputPoint: PointF): Boolean {
+ if (!viewsLaidOut()) return true
+ if (!isViewAboveStatusBar) {
+ return pointInView(
+ handleMenuViewContainer?.view,
+ inputPoint.x - handleMenuPosition.x,
+ inputPoint.y - handleMenuPosition.y
+ )
+ } else {
+ // Handle menu exists in a different coordinate space when added to WindowManager.
+ // Therefore we must compare the provided input coordinates to global menu coordinates.
+ // This includes factoring for split stage as input coordinates are relative to split
+ // stage position, not relative to the display as a whole.
+ val inputRelativeToMenu = PointF(
+ inputPoint.x - globalMenuPosition.x,
+ inputPoint.y - globalMenuPosition.y
+ )
+ if (splitScreenController.getSplitPosition(taskInfo.taskId)
+ == SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT) {
+ // TODO(b/343561161): This also needs to be calculated differently if
+ // the task is in top/bottom split.
+ val leftStageBounds = Rect()
+ splitScreenController.getStageBounds(leftStageBounds, Rect())
+ inputRelativeToMenu.x += leftStageBounds.width().toFloat()
+ }
+ return pointInView(
+ handleMenuViewContainer?.view,
+ inputRelativeToMenu.x,
+ inputRelativeToMenu.y
+ )
+ }
+ }
+
+ private fun pointInView(v: View?, x: Float, y: Float): Boolean {
+ return v != null && v.left <= x && v.right >= x && v.top <= y && v.bottom >= y
+ }
+
+ /**
+ * Check if the views for handle menu can be seen.
+ */
+ private fun viewsLaidOut(): Boolean = handleMenuViewContainer?.view?.isLaidOut ?: false
+
+ /**
+ * Determines handle menu height based the max size and the visibility of pills.
+ */
+ private fun getHandleMenuHeight(): Int {
+ var menuHeight = loadDimensionPixelSize(
+ R.dimen.desktop_mode_handle_menu_height) + pillElevation
+ if (!shouldShowWindowingPill) {
+ menuHeight -= loadDimensionPixelSize(
+ R.dimen.desktop_mode_handle_menu_windowing_pill_height)
+ menuHeight -= pillTopMargin
+ }
+ if (!SHOULD_SHOW_MORE_ACTIONS_PILL) {
+ menuHeight -= loadDimensionPixelSize(
+ R.dimen.desktop_mode_handle_menu_more_actions_pill_height)
+ menuHeight -= pillTopMargin
+ }
+ if (!shouldShowBrowserPill) {
+ menuHeight -= loadDimensionPixelSize(
+ R.dimen.desktop_mode_handle_menu_open_in_browser_pill_height)
+ menuHeight -= pillTopMargin
+ }
+ return menuHeight
+ }
+
+ private fun loadDimensionPixelSize(@DimenRes resourceId: Int): Int {
+ if (resourceId == Resources.ID_NULL) {
+ return 0
+ }
+ return context.resources.getDimensionPixelSize(resourceId)
+ }
+
+ fun close() {
+ val after = {
+ handleMenuViewContainer?.releaseView()
+ handleMenuViewContainer = null
+ }
+ if (taskInfo.windowingMode == WINDOWING_MODE_FULLSCREEN ||
+ taskInfo.windowingMode == WINDOWING_MODE_MULTI_WINDOW) {
+ handleMenuAnimator?.animateCollapseIntoHandleClose(after)
+ } else {
+ handleMenuAnimator?.animateClose(after)
+ }
+ }
+
+ companion object {
+ private const val TAG = "HandleMenu"
+ private const val SHOULD_SHOW_MORE_ACTIONS_PILL = false
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenuAnimator.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenuAnimator.kt
index 25a829b44448..e3d22342cc9b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenuAnimator.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenuAnimator.kt
@@ -108,7 +108,7 @@ class HandleMenuAnimator(
*
* @param after runs after the animation finishes.
*/
- fun animateCollapseIntoHandleClose(after: Runnable) {
+ fun animateCollapseIntoHandleClose(after: () -> Unit) {
appInfoCollapseToHandle()
animateAppInfoPillFadeOut()
windowingPillClose()
@@ -125,7 +125,7 @@ class HandleMenuAnimator(
* @param after runs after animation finishes.
*
*/
- fun animateClose(after: Runnable) {
+ fun animateClose(after: () -> Unit) {
appInfoPillCollapse()
animateAppInfoPillFadeOut()
windowingPillClose()
@@ -463,9 +463,9 @@ class HandleMenuAnimator(
*
* @param after runs after animation finishes.
*/
- private fun runAnimations(after: Runnable? = null) {
+ private fun runAnimations(after: (() -> Unit)? = null) {
runningAnimation?.apply {
- // Remove all listeners, so that after runnable isn't triggered upon cancel.
+ // Remove all listeners, so that the after function isn't triggered upon cancel.
removeAllListeners()
// If an animation runs while running animation is triggered, gracefully cancel.
cancel()
@@ -475,7 +475,7 @@ class HandleMenuAnimator(
playTogether(animators)
animators.clear()
doOnEnd {
- after?.run()
+ after?.invoke()
runningAnimation = null
}
start()
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
index 03dbbb3bbb82..d212f2131ed4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
@@ -19,6 +19,7 @@ package com.android.wm.shell.windowdecor;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.content.res.Configuration.DENSITY_DPI_UNDEFINED;
+import static android.view.InsetsSource.FLAG_FORCE_CONSUMING;
import static android.view.WindowInsets.Type.captionBar;
import static android.view.WindowInsets.Type.mandatorySystemGestures;
import static android.view.WindowInsets.Type.statusBars;
@@ -53,6 +54,7 @@ import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.window.flags.Flags;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
@@ -105,7 +107,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
* System-wide context. Only used to create context with overridden configurations.
*/
final Context mContext;
- final DisplayController mDisplayController;
+ final @NonNull DisplayController mDisplayController;
final ShellTaskOrganizer mTaskOrganizer;
final Supplier<SurfaceControl.Builder> mSurfaceControlBuilderSupplier;
final Supplier<SurfaceControl.Transaction> mSurfaceControlTransactionSupplier;
@@ -158,7 +160,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
WindowDecoration(
Context context,
- DisplayController displayController,
+ @NonNull DisplayController displayController,
ShellTaskOrganizer taskOrganizer,
RunningTaskInfo taskInfo,
@NonNull SurfaceControl taskSurface,
@@ -759,9 +761,12 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
}
void addOrUpdate(WindowContainerTransaction wct) {
- wct.addInsetsSource(mToken, mOwner, INDEX, captionBar(), mFrame, mBoundingRects);
+ final @InsetsSource.Flags int captionSourceFlags =
+ Flags.enableCaptionCompatInsetForceConsumption() ? FLAG_FORCE_CONSUMING : 0;
+ wct.addInsetsSource(mToken, mOwner, INDEX, captionBar(), mFrame, mBoundingRects,
+ captionSourceFlags);
wct.addInsetsSource(mToken, mOwner, INDEX, mandatorySystemGestures(), mFrame,
- mBoundingRects);
+ mBoundingRects, 0 /* flags */);
}
void remove(WindowContainerTransaction wct) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/additionalviewcontainer/AdditionalSystemViewContainer.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/additionalviewcontainer/AdditionalSystemViewContainer.kt
index 6c2c8fd46bc9..4897f76a20cf 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/additionalviewcontainer/AdditionalSystemViewContainer.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/additionalviewcontainer/AdditionalSystemViewContainer.kt
@@ -18,6 +18,7 @@ package com.android.wm.shell.windowdecor.additionalviewcontainer
import android.content.Context
import android.graphics.PixelFormat
+import android.view.Gravity
import android.view.LayoutInflater
import android.view.SurfaceControl
import android.view.View
@@ -45,9 +46,11 @@ class AdditionalSystemViewContainer(
WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSPARENT
- )
- lp.title = "Additional view container of Task=$taskId"
- lp.setTrustedOverlay()
+ ).apply {
+ title = "Additional view container of Task=$taskId"
+ gravity = Gravity.LEFT or Gravity.TOP
+ setTrustedOverlay()
+ }
val wm: WindowManager? = context.getSystemService(WindowManager::class.java)
wm?.addView(view, lp)
}
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/desktopmode/scenarios/ExitDesktopWithDragToTopDragZone.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/desktopmode/scenarios/ExitDesktopWithDragToTopDragZone.kt
new file mode 100644
index 000000000000..0b6c9af17e7a
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/desktopmode/scenarios/ExitDesktopWithDragToTopDragZone.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.wm.shell.flicker.service.desktopmode.scenarios
+
+import android.app.Instrumentation
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.server.wm.flicker.helpers.DesktopModeAppHelper
+import com.android.server.wm.flicker.helpers.SimpleAppHelper
+import com.android.window.flags.Flags
+import com.android.wm.shell.flicker.service.common.Utils
+import org.junit.After
+import org.junit.Assume
+import org.junit.Before
+import org.junit.Ignore
+import org.junit.Rule
+import org.junit.Test
+
+
+@Ignore("Base Test Class")
+abstract class ExitDesktopWithDragToTopDragZone
+@JvmOverloads
+constructor(val rotation: Rotation = Rotation.ROTATION_0) {
+
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val tapl = LauncherInstrumentation()
+ private val wmHelper = WindowManagerStateHelper(instrumentation)
+ private val device = UiDevice.getInstance(instrumentation)
+ private val testApp = DesktopModeAppHelper(SimpleAppHelper(instrumentation))
+
+ @Rule @JvmField val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, rotation)
+
+ @Before
+ fun setup() {
+ Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet)
+ tapl.setEnableRotation(true)
+ tapl.setExpectedRotation(rotation.value)
+ testApp.enterDesktopWithDrag(wmHelper, device)
+ }
+
+ @Test
+ open fun exitDesktopWithDragToTopDragZone() {
+ testApp.exitDesktopWithDragToTopDragZone(wmHelper, device)
+ }
+
+ @After
+ fun teardown() {
+ testApp.exit(wmHelper)
+ }
+}
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 6cabbf90bbc2..8558a77e4e7e 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
@@ -311,6 +311,25 @@ class DesktopTasksControllerTest : ShellTestCase() {
}
@Test
+ @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY)
+ fun showDesktopApps_onSecondaryDisplay_desktopWallpaperEnabled_shouldNotShowWallpaper() {
+ val homeTask = setUpHomeTask(SECOND_DISPLAY)
+ val task1 = setUpFreeformTask(SECOND_DISPLAY)
+ val task2 = setUpFreeformTask(SECOND_DISPLAY)
+ markTaskHidden(task1)
+ markTaskHidden(task2)
+
+ controller.showDesktopApps(SECOND_DISPLAY, RemoteTransition(TestRemoteTransition()))
+
+ val wct = getLatestWct(type = TRANSIT_TO_FRONT, handlerClass = OneShotRemoteHandler::class.java)
+ assertThat(wct.hierarchyOps).hasSize(3)
+ // Expect order to be from bottom: home, task1, task2 (no wallpaper intent)
+ wct.assertReorderAt(index = 0, homeTask)
+ wct.assertReorderAt(index = 1, task1)
+ wct.assertReorderAt(index = 2, task2)
+ }
+
+ @Test
@DisableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY)
fun showDesktopApps_appsAlreadyVisible_bringsToFront_desktopWallpaperDisabled() {
val homeTask = setUpHomeTask()
@@ -330,6 +349,25 @@ class DesktopTasksControllerTest : ShellTestCase() {
}
@Test
+ @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY)
+ fun showDesktopApps_onSecondaryDisplay_desktopWallpaperDisabled_shouldNotMoveLauncher() {
+ val homeTask = setUpHomeTask(SECOND_DISPLAY)
+ val task1 = setUpFreeformTask(SECOND_DISPLAY)
+ val task2 = setUpFreeformTask(SECOND_DISPLAY)
+ markTaskHidden(task1)
+ markTaskHidden(task2)
+
+ controller.showDesktopApps(SECOND_DISPLAY, RemoteTransition(TestRemoteTransition()))
+
+ val wct = getLatestWct(type = TRANSIT_TO_FRONT, handlerClass = OneShotRemoteHandler::class.java)
+ assertThat(wct.hierarchyOps).hasSize(3)
+ // Expect order to be from bottom: home, task1, task2
+ wct.assertReorderAt(index = 0, homeTask)
+ wct.assertReorderAt(index = 1, task1)
+ wct.assertReorderAt(index = 2, task2)
+ }
+
+ @Test
@EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY)
fun showDesktopApps_appsAlreadyVisible_bringsToFront_desktopWallpaperEnabled() {
val task1 = setUpFreeformTask()
@@ -427,6 +465,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
@Test
@EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY)
fun showDesktopApps_twoDisplays_bringsToFrontOnlyOneDisplay_desktopWallpaperEnabled() {
+ val homeTaskDefaultDisplay = setUpHomeTask(DEFAULT_DISPLAY)
val taskDefaultDisplay = setUpFreeformTask(DEFAULT_DISPLAY)
setUpHomeTask(SECOND_DISPLAY)
val taskSecondDisplay = setUpFreeformTask(SECOND_DISPLAY)
@@ -436,10 +475,13 @@ class DesktopTasksControllerTest : ShellTestCase() {
controller.showDesktopApps(DEFAULT_DISPLAY, RemoteTransition(TestRemoteTransition()))
val wct = getLatestWct(type = TRANSIT_TO_FRONT, handlerClass = OneShotRemoteHandler::class.java)
- assertThat(wct.hierarchyOps).hasSize(2)
- // Expect order to be from bottom: wallpaper intent, task
- wct.assertPendingIntentAt(index = 0, desktopWallpaperIntent)
- wct.assertReorderAt(index = 1, taskDefaultDisplay)
+ assertThat(wct.hierarchyOps).hasSize(3)
+ // Move home to front
+ wct.assertReorderAt(index = 0, homeTaskDefaultDisplay)
+ // Add desktop wallpaper activity
+ wct.assertPendingIntentAt(index = 1, desktopWallpaperIntent)
+ // Move freeform task to front
+ wct.assertReorderAt(index = 2, taskDefaultDisplay)
}
@Test
@@ -464,7 +506,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
@Test
@EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY)
fun showDesktopApps_desktopWallpaperEnabled_dontReorderMinimizedTask() {
- setUpHomeTask()
+ val homeTask = setUpHomeTask()
val freeformTask = setUpFreeformTask()
val minimizedTask = setUpFreeformTask()
@@ -474,11 +516,13 @@ class DesktopTasksControllerTest : ShellTestCase() {
controller.showDesktopApps(DEFAULT_DISPLAY, RemoteTransition(TestRemoteTransition()))
val wct = getLatestWct(type = TRANSIT_TO_FRONT, handlerClass = OneShotRemoteHandler::class.java)
- assertThat(wct.hierarchyOps).hasSize(2)
+ assertThat(wct.hierarchyOps).hasSize(3)
+ // Move home to front
+ wct.assertReorderAt(index = 0, homeTask, toTop = true)
// Add desktop wallpaper activity
- wct.assertPendingIntentAt(index = 0, desktopWallpaperIntent)
+ wct.assertPendingIntentAt(index = 1, desktopWallpaperIntent)
// Reorder freeform task to top, don't reorder the minimized task
- wct.assertReorderAt(index = 1, freeformTask, toTop = true)
+ wct.assertReorderAt(index = 2, freeformTask, toTop = true)
}
@Test
@@ -861,16 +905,19 @@ class DesktopTasksControllerTest : ShellTestCase() {
val taskLimit = desktopTasksLimiter.getMaxTaskLimit()
val freeformTasks = (1..taskLimit).map { _ -> setUpFreeformTask() }
val newTask = setUpFullscreenTask()
- setUpHomeTask()
+ val homeTask = setUpHomeTask()
controller.moveToDesktop(newTask, transitionSource = UNKNOWN)
val wct = getLatestEnterDesktopWct()
- assertThat(wct.hierarchyOps.size).isEqualTo(taskLimit + 1) // visible tasks + wallpaper
+ assertThat(wct.hierarchyOps.size).isEqualTo(taskLimit + 2) // tasks + home + wallpaper
+ // Move home to front
+ wct.assertReorderAt(0, homeTask)
// Add desktop wallpaper activity
- wct.assertPendingIntentAt(0, desktopWallpaperIntent)
+ wct.assertPendingIntentAt(1, desktopWallpaperIntent)
+ // Bring freeform tasks to front
wct.assertReorderSequenceInRange(
- range = 1..<(taskLimit + 1),
+ range = 2..<(taskLimit + 2),
*freeformTasks.drop(1).toTypedArray(), // Skipping freeformTasks[0]
newTask
)
@@ -888,6 +935,24 @@ class DesktopTasksControllerTest : ShellTestCase() {
}
@Test
+ fun moveToFullscreen_tdaFullscreen_windowingModeUndefined_removesWallpaperActivity() {
+ val task = setUpFreeformTask()
+ val wallpaperToken = MockToken().token()
+
+ desktopModeTaskRepository.wallpaperActivityToken = wallpaperToken
+ assertNotNull(rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY))
+ .configuration.windowConfiguration.windowingMode = WINDOWING_MODE_FULLSCREEN
+
+ controller.moveToFullscreen(task.taskId, transitionSource = UNKNOWN)
+
+ val wct = getLatestExitDesktopWct()
+ val taskChange = assertNotNull(wct.changes[task.token.asBinder()])
+ assertThat(taskChange.windowingMode).isEqualTo(WINDOWING_MODE_UNDEFINED)
+ // Removes wallpaper activity when leaving desktop
+ wct.assertRemoveAt(index = 0, wallpaperToken)
+ }
+
+ @Test
fun moveToFullscreen_tdaFreeform_windowingModeSetToFullscreen() {
val task = setUpFreeformTask()
val tda = rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY)!!
@@ -899,6 +964,44 @@ class DesktopTasksControllerTest : ShellTestCase() {
}
@Test
+ fun moveToFullscreen_tdaFreeform_windowingModeFullscreen_removesWallpaperActivity() {
+ val task = setUpFreeformTask()
+ val wallpaperToken = MockToken().token()
+
+ desktopModeTaskRepository.wallpaperActivityToken = wallpaperToken
+ assertNotNull(rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY))
+ .configuration.windowConfiguration.windowingMode = WINDOWING_MODE_FREEFORM
+
+ controller.moveToFullscreen(task.taskId, transitionSource = UNKNOWN)
+
+ val wct = getLatestExitDesktopWct()
+ val taskChange = assertNotNull(wct.changes[task.token.asBinder()])
+ assertThat(taskChange.windowingMode).isEqualTo(WINDOWING_MODE_FULLSCREEN)
+ // Removes wallpaper activity when leaving desktop
+ wct.assertRemoveAt(index = 0, wallpaperToken)
+ }
+
+ @Test
+ fun moveToFullscreen_multipleVisibleNonMinimizedTasks_doesNotRemoveWallpaperActivity() {
+ val task1 = setUpFreeformTask()
+ // Setup task2
+ setUpFreeformTask()
+ val wallpaperToken = MockToken().token()
+
+ desktopModeTaskRepository.wallpaperActivityToken = wallpaperToken
+ assertNotNull(rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY))
+ .configuration.windowConfiguration.windowingMode = WINDOWING_MODE_FULLSCREEN
+
+ controller.moveToFullscreen(task1.taskId, transitionSource = UNKNOWN)
+
+ val wct = getLatestExitDesktopWct()
+ val task1Change = assertNotNull(wct.changes[task1.token.asBinder()])
+ assertThat(task1Change.windowingMode).isEqualTo(WINDOWING_MODE_UNDEFINED)
+ // Does not remove wallpaper activity, as desktop still has a visible desktop task
+ assertThat(wct.hierarchyOps).isEmpty()
+ }
+
+ @Test
fun moveToFullscreen_nonExistentTask_doesNothing() {
controller.moveToFullscreen(999, transitionSource = UNKNOWN)
verifyExitDesktopWCTNotExecuted()
@@ -1722,6 +1825,49 @@ class DesktopTasksControllerTest : ShellTestCase() {
}
@Test
+ fun moveFocusedTaskToFullscreen_onlyVisibleNonMinimizedTask_removesWallpaperActivity() {
+ val task1 = setUpFreeformTask()
+ val task2 = setUpFreeformTask()
+ val task3 = setUpFreeformTask()
+ val wallpaperToken = MockToken().token()
+
+ task1.isFocused = false
+ task2.isFocused = true
+ task3.isFocused = false
+ desktopModeTaskRepository.wallpaperActivityToken = wallpaperToken
+ desktopModeTaskRepository.minimizeTask(DEFAULT_DISPLAY, task1.taskId)
+ desktopModeTaskRepository.updateVisibleFreeformTasks(DEFAULT_DISPLAY, task3.taskId,
+ visible = false)
+
+ controller.enterFullscreen(DEFAULT_DISPLAY, transitionSource = UNKNOWN)
+
+ val wct = getLatestExitDesktopWct()
+ val taskChange = assertNotNull(wct.changes[task2.token.asBinder()])
+ assertThat(taskChange.windowingMode).isEqualTo(WINDOWING_MODE_UNDEFINED) // inherited FULLSCREEN
+ wct.assertRemoveAt(index = 0, wallpaperToken)
+ }
+
+ @Test
+ fun moveFocusedTaskToFullscreen_multipleVisibleTasks_doesNotRemoveWallpaperActivity() {
+ val task1 = setUpFreeformTask()
+ val task2 = setUpFreeformTask()
+ val task3 = setUpFreeformTask()
+ val wallpaperToken = MockToken().token()
+
+ task1.isFocused = false
+ task2.isFocused = true
+ task3.isFocused = false
+ desktopModeTaskRepository.wallpaperActivityToken = wallpaperToken
+ controller.enterFullscreen(DEFAULT_DISPLAY, transitionSource = UNKNOWN)
+
+ val wct = getLatestExitDesktopWct()
+ val taskChange = assertNotNull(wct.changes[task2.token.asBinder()])
+ assertThat(taskChange.windowingMode).isEqualTo(WINDOWING_MODE_UNDEFINED) // inherited FULLSCREEN
+ // Does not remove wallpaper activity, as desktop still has visible desktop tasks
+ assertThat(wct.hierarchyOps).isEmpty()
+ }
+
+ @Test
@EnableFlags(Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS)
fun dragToDesktop_landscapeDevice_resizable_undefinedOrientation_defaultLandscapeBounds() {
val spyController = spy(controller)
@@ -1930,6 +2076,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
eq(null))
}
+ @Test
fun enterSplit_freeformTaskIsMovedToSplit() {
val task1 = setUpFreeformTask()
val task2 = setUpFreeformTask()
@@ -1939,14 +2086,67 @@ class DesktopTasksControllerTest : ShellTestCase() {
task2.isFocused = true
task3.isFocused = false
- controller.enterSplit(DEFAULT_DISPLAY, false)
+ controller.enterSplit(DEFAULT_DISPLAY, leftOrTop = false)
verify(splitScreenController)
.requestEnterSplitSelect(
- task2,
+ eq(task2),
any(),
- SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT,
- task2.configuration.windowConfiguration.bounds)
+ eq(SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT),
+ eq(task2.configuration.windowConfiguration.bounds))
+ }
+
+ @Test
+ fun enterSplit_onlyVisibleNonMinimizedTask_removesWallpaperActivity() {
+ val task1 = setUpFreeformTask()
+ val task2 = setUpFreeformTask()
+ val task3 = setUpFreeformTask()
+ val wallpaperToken = MockToken().token()
+
+ task1.isFocused = false
+ task2.isFocused = true
+ task3.isFocused = false
+ desktopModeTaskRepository.wallpaperActivityToken = wallpaperToken
+ desktopModeTaskRepository.minimizeTask(DEFAULT_DISPLAY, task1.taskId)
+ desktopModeTaskRepository.updateVisibleFreeformTasks(DEFAULT_DISPLAY, task3.taskId,
+ visible = false)
+
+ controller.enterSplit(DEFAULT_DISPLAY, leftOrTop = false)
+
+ val wctArgument = ArgumentCaptor.forClass(WindowContainerTransaction::class.java)
+ verify(splitScreenController)
+ .requestEnterSplitSelect(
+ eq(task2),
+ wctArgument.capture(),
+ eq(SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT),
+ eq(task2.configuration.windowConfiguration.bounds))
+ // Removes wallpaper activity when leaving desktop
+ wctArgument.value.assertRemoveAt(index = 0, wallpaperToken)
+ }
+
+ @Test
+ fun enterSplit_multipleVisibleNonMinimizedTasks_removesWallpaperActivity() {
+ val task1 = setUpFreeformTask()
+ val task2 = setUpFreeformTask()
+ val task3 = setUpFreeformTask()
+ val wallpaperToken = MockToken().token()
+
+ task1.isFocused = false
+ task2.isFocused = true
+ task3.isFocused = false
+ desktopModeTaskRepository.wallpaperActivityToken = wallpaperToken
+
+ controller.enterSplit(DEFAULT_DISPLAY, leftOrTop = false)
+
+ val wctArgument = ArgumentCaptor.forClass(WindowContainerTransaction::class.java)
+ verify(splitScreenController)
+ .requestEnterSplitSelect(
+ eq(task2),
+ wctArgument.capture(),
+ eq(SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT),
+ eq(task2.configuration.windowConfiguration.bounds))
+ // Does not remove wallpaper activity, as desktop still has visible desktop tasks
+ assertThat(wctArgument.value.hierarchyOps).isEmpty()
}
@Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/DefaultTransitionHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/DefaultTransitionHandlerTest.java
index 754a173ff069..6bc7e499159c 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/DefaultTransitionHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/DefaultTransitionHandlerTest.java
@@ -17,6 +17,7 @@
package com.android.wm.shell.transition;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_SLEEP;
@@ -185,6 +186,73 @@ public class DefaultTransitionHandlerTest extends ShellTestCase {
verify(startT, never()).setColor(any(), any());
}
+ @Test
+ public void startAnimation_freeformOpenChange_doesntReparentTask() {
+ final TransitionInfo.Change openChange = new ChangeBuilder(TRANSIT_OPEN)
+ .setTask(createTaskInfo(
+ /* taskId= */ 1, /* windowingMode= */ WINDOWING_MODE_FULLSCREEN))
+ .build();
+ final TransitionInfo info = new TransitionInfoBuilder(TRANSIT_OPEN)
+ .addChange(openChange)
+ .build();
+ final IBinder token = new Binder();
+ final SurfaceControl.Transaction startT = MockTransactionPool.create();
+ final SurfaceControl.Transaction finishT = MockTransactionPool.create();
+
+ mTransitionHandler.startAnimation(token, info, startT, finishT,
+ mock(Transitions.TransitionFinishCallback.class));
+
+ verify(startT, never()).reparent(any(), any());
+ }
+
+ @Test
+ public void startAnimation_freeformMinimizeChange_underFullscreenChange_doesntReparentTask() {
+ final TransitionInfo.Change openChange = new ChangeBuilder(TRANSIT_OPEN)
+ .setTask(createTaskInfo(
+ /* taskId= */ 1, /* windowingMode= */ WINDOWING_MODE_FULLSCREEN))
+ .build();
+ final TransitionInfo.Change toBackChange = new ChangeBuilder(TRANSIT_TO_BACK)
+ .setTask(createTaskInfo(
+ /* taskId= */ 2, /* windowingMode= */ WINDOWING_MODE_FREEFORM))
+ .build();
+ final TransitionInfo info = new TransitionInfoBuilder(TRANSIT_OPEN)
+ .addChange(openChange)
+ .addChange(toBackChange)
+ .build();
+ final IBinder token = new Binder();
+ final SurfaceControl.Transaction startT = MockTransactionPool.create();
+ final SurfaceControl.Transaction finishT = MockTransactionPool.create();
+
+ mTransitionHandler.startAnimation(token, info, startT, finishT,
+ mock(Transitions.TransitionFinishCallback.class));
+
+ verify(startT, never()).reparent(any(), any());
+ }
+
+ @Test
+ public void startAnimation_freeform_minimizeAnimation_reparentsTask() {
+ final TransitionInfo.Change openChange = new ChangeBuilder(TRANSIT_OPEN)
+ .setTask(createTaskInfo(
+ /* taskId= */ 1, /* windowingMode= */ WINDOWING_MODE_FREEFORM))
+ .build();
+ final TransitionInfo.Change toBackChange = new ChangeBuilder(TRANSIT_TO_BACK)
+ .setTask(createTaskInfo(
+ /* taskId= */ 2, /* windowingMode= */ WINDOWING_MODE_FREEFORM))
+ .build();
+ final TransitionInfo info = new TransitionInfoBuilder(TRANSIT_OPEN)
+ .addChange(openChange)
+ .addChange(toBackChange)
+ .build();
+ final IBinder token = new Binder();
+ final SurfaceControl.Transaction startT = MockTransactionPool.create();
+ final SurfaceControl.Transaction finishT = MockTransactionPool.create();
+
+ mTransitionHandler.startAnimation(token, info, startT, finishT,
+ mock(Transitions.TransitionFinishCallback.class));
+
+ verify(startT).reparent(any(), any());
+ }
+
private static void mergeSync(Transitions.TransitionHandler handler, IBinder token) {
handler.mergeAnimation(
new Binder(),
@@ -195,10 +263,14 @@ public class DefaultTransitionHandlerTest extends ShellTestCase {
}
private static RunningTaskInfo createTaskInfo(int taskId) {
+ return createTaskInfo(taskId, WINDOWING_MODE_FULLSCREEN);
+ }
+
+ private static RunningTaskInfo createTaskInfo(int taskId, int windowingMode) {
RunningTaskInfo taskInfo = new RunningTaskInfo();
taskInfo.taskId = taskId;
taskInfo.topActivityType = ACTIVITY_TYPE_STANDARD;
- taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ taskInfo.configuration.windowConfiguration.setWindowingMode(windowingMode);
taskInfo.configuration.windowConfiguration.setActivityType(taskInfo.topActivityType);
taskInfo.token = mock(WindowContainerToken.class);
return taskInfo;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/TransitionAnimationHelperTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/TransitionAnimationHelperTest.kt
new file mode 100644
index 000000000000..bad14bbdb141
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/TransitionAnimationHelperTest.kt
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.transition
+
+import android.app.ActivityManager.RunningTaskInfo
+import android.app.WindowConfiguration
+import android.view.WindowManager
+import android.window.TransitionInfo
+import android.window.TransitionInfo.FLAG_TRANSLUCENT
+import com.android.internal.R
+import com.android.internal.policy.TransitionAnimation
+import com.android.wm.shell.ShellTestCase
+import com.android.wm.shell.TestRunningTaskInfoBuilder
+import org.junit.Test
+import org.mockito.ArgumentMatchers.anyBoolean
+import org.mockito.ArgumentMatchers.eq
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+
+class TransitionAnimationHelperTest : ShellTestCase() {
+
+ @Mock
+ lateinit var transitionAnimation: TransitionAnimation
+
+ @Test
+ fun loadAttributeAnimation_freeform_taskOpen_taskToBackChange_returnsMinimizeAnim() {
+ val openChange = ChangeBuilder(WindowManager.TRANSIT_OPEN)
+ .setTask(createTaskInfo(WindowConfiguration.WINDOWING_MODE_FREEFORM))
+ .build()
+ val toBackChange = ChangeBuilder(WindowManager.TRANSIT_TO_BACK)
+ .setTask(createTaskInfo(WindowConfiguration.WINDOWING_MODE_FREEFORM))
+ .build()
+ val info = TransitionInfoBuilder(WindowManager.TRANSIT_OPEN)
+ .addChange(openChange)
+ .addChange(toBackChange)
+ .build()
+
+ loadAttributeAnimation(WindowManager.TRANSIT_OPEN, info, toBackChange)
+
+ verify(transitionAnimation).loadDefaultAnimationAttr(
+ eq(R.styleable.WindowAnimation_activityCloseExitAnimation), anyBoolean())
+ }
+
+ @Test
+ fun loadAttributeAnimation_freeform_taskToFront_taskToFrontChange_returnsUnminimizeAnim() {
+ val toFrontChange = ChangeBuilder(WindowManager.TRANSIT_TO_FRONT)
+ .setTask(createTaskInfo(WindowConfiguration.WINDOWING_MODE_FREEFORM))
+ .build()
+ val info = TransitionInfoBuilder(WindowManager.TRANSIT_TO_FRONT)
+ .addChange(toFrontChange)
+ .build()
+
+ loadAttributeAnimation(WindowManager.TRANSIT_TO_FRONT, info, toFrontChange)
+
+ verify(transitionAnimation).loadDefaultAnimationAttr(
+ eq(R.styleable.WindowAnimation_activityOpenEnterAnimation),
+ /* translucent= */ anyBoolean())
+ }
+
+ @Test
+ fun loadAttributeAnimation_fullscreen_taskOpen_returnsTaskOpenEnterAnim() {
+ val openChange = ChangeBuilder(WindowManager.TRANSIT_OPEN)
+ .setTask(createTaskInfo(WindowConfiguration.WINDOWING_MODE_FULLSCREEN))
+ .build()
+ val info = TransitionInfoBuilder(WindowManager.TRANSIT_OPEN).addChange(openChange).build()
+
+ loadAttributeAnimation(WindowManager.TRANSIT_OPEN, info, openChange)
+
+ verify(transitionAnimation).loadDefaultAnimationAttr(
+ eq(R.styleable.WindowAnimation_taskOpenEnterAnimation),
+ /* translucent= */ anyBoolean())
+ }
+
+ @Test
+ fun loadAttributeAnimation_freeform_taskOpen_taskToBackChange_passesTranslucent() {
+ val openChange = ChangeBuilder(WindowManager.TRANSIT_OPEN)
+ .setTask(createTaskInfo(WindowConfiguration.WINDOWING_MODE_FREEFORM))
+ .build()
+ val toBackChange = ChangeBuilder(WindowManager.TRANSIT_TO_BACK)
+ .setTask(createTaskInfo(WindowConfiguration.WINDOWING_MODE_FREEFORM))
+ .setFlags(FLAG_TRANSLUCENT)
+ .build()
+ val info = TransitionInfoBuilder(WindowManager.TRANSIT_OPEN)
+ .addChange(openChange)
+ .addChange(toBackChange)
+ .build()
+
+ loadAttributeAnimation(WindowManager.TRANSIT_OPEN, info, toBackChange)
+
+ verify(transitionAnimation).loadDefaultAnimationAttr(
+ eq(R.styleable.WindowAnimation_activityCloseExitAnimation),
+ /* translucent= */ eq(true))
+ }
+
+ private fun loadAttributeAnimation(
+ @WindowManager.TransitionType type: Int,
+ info: TransitionInfo,
+ change: TransitionInfo.Change,
+ wallpaperTransit: Int = TransitionAnimation.WALLPAPER_TRANSITION_NONE,
+ isDreamTransition: Boolean = false,
+ ) {
+ TransitionAnimationHelper.loadAttributeAnimation(
+ type, info, change, wallpaperTransit, transitionAnimation, isDreamTransition)
+ }
+
+ private fun createTaskInfo(windowingMode: Int): RunningTaskInfo {
+ val taskInfo = TestRunningTaskInfoBuilder()
+ .setWindowingMode(windowingMode)
+ .build()
+ return taskInfo
+ }
+} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/CaptionWindowDecorationTests.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/CaptionWindowDecorationTests.kt
new file mode 100644
index 000000000000..261d4b5e7d1a
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/CaptionWindowDecorationTests.kt
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.windowdecor
+
+import android.app.ActivityManager
+import android.app.WindowConfiguration
+import android.content.ComponentName
+import android.testing.AndroidTestingRunner
+import android.view.Display
+import android.view.WindowInsetsController
+import androidx.test.filters.SmallTest
+import com.android.wm.shell.ShellTestCase
+import com.android.wm.shell.TestRunningTaskInfoBuilder
+import com.google.common.truth.Truth
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class CaptionWindowDecorationTests : ShellTestCase() {
+ @Test
+ fun updateRelayoutParams_freeformAndTransparentAppearance_allowsInputFallthrough() {
+ val taskInfo = createTaskInfo()
+ taskInfo.configuration.windowConfiguration.windowingMode =
+ WindowConfiguration.WINDOWING_MODE_FREEFORM
+ taskInfo.taskDescription!!.topOpaqueSystemBarsAppearance =
+ WindowInsetsController.APPEARANCE_TRANSPARENT_CAPTION_BAR_BACKGROUND
+ val relayoutParams = WindowDecoration.RelayoutParams()
+
+ CaptionWindowDecoration.updateRelayoutParams(
+ relayoutParams,
+ taskInfo,
+ true,
+ false
+ )
+
+ Truth.assertThat(relayoutParams.hasInputFeatureSpy()).isTrue()
+ }
+
+ @Test
+ fun updateRelayoutParams_freeformButOpaqueAppearance_disallowsInputFallthrough() {
+ val taskInfo = createTaskInfo()
+ taskInfo.configuration.windowConfiguration.windowingMode =
+ WindowConfiguration.WINDOWING_MODE_FREEFORM
+ taskInfo.taskDescription!!.topOpaqueSystemBarsAppearance = 0
+ val relayoutParams = WindowDecoration.RelayoutParams()
+
+ CaptionWindowDecoration.updateRelayoutParams(
+ relayoutParams,
+ taskInfo,
+ true,
+ false
+ )
+
+ Truth.assertThat(relayoutParams.hasInputFeatureSpy()).isFalse()
+ }
+
+ @Test
+ fun updateRelayoutParams_addOccludingCaptionElementCorrectly() {
+ val taskInfo = createTaskInfo()
+ val relayoutParams = WindowDecoration.RelayoutParams()
+ CaptionWindowDecoration.updateRelayoutParams(
+ relayoutParams,
+ taskInfo,
+ true,
+ false
+ )
+ Truth.assertThat(relayoutParams.mOccludingCaptionElements.size).isEqualTo(2)
+ Truth.assertThat(relayoutParams.mOccludingCaptionElements[0].mAlignment).isEqualTo(
+ WindowDecoration.RelayoutParams.OccludingCaptionElement.Alignment.START)
+ Truth.assertThat(relayoutParams.mOccludingCaptionElements[1].mAlignment).isEqualTo(
+ WindowDecoration.RelayoutParams.OccludingCaptionElement.Alignment.END)
+ }
+
+ private fun createTaskInfo(): ActivityManager.RunningTaskInfo {
+ val taskDescriptionBuilder =
+ ActivityManager.TaskDescription.Builder()
+ val taskInfo = TestRunningTaskInfoBuilder()
+ .setDisplayId(Display.DEFAULT_DISPLAY)
+ .setTaskDescriptionBuilder(taskDescriptionBuilder)
+ .setVisible(true)
+ .build()
+ taskInfo.realActivity = ComponentName(
+ "com.android.wm.shell.windowdecor",
+ "CaptionWindowDecorationTests"
+ )
+ taskInfo.baseActivity = ComponentName(
+ "com.android.wm.shell.windowdecor",
+ "CaptionWindowDecorationTests"
+ )
+ return taskInfo
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometryTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometryTests.java
index 4dea5a75a0e8..6a94cd8aa283 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometryTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometryTests.java
@@ -55,8 +55,6 @@ public class DragResizeWindowGeometryTests {
private static final Size TASK_SIZE = new Size(500, 1000);
private static final int TASK_CORNER_RADIUS = 10;
private static final int EDGE_RESIZE_THICKNESS = 15;
- private static final int EDGE_RESIZE_DEBUG_THICKNESS = EDGE_RESIZE_THICKNESS
- + (DragResizeWindowGeometry.DEBUG ? DragResizeWindowGeometry.EDGE_DEBUG_BUFFER : 0);
private static final int FINE_CORNER_SIZE = EDGE_RESIZE_THICKNESS * 2 + 10;
private static final int LARGE_CORNER_SIZE = FINE_CORNER_SIZE + 10;
private static final DragResizeWindowGeometry GEOMETRY = new DragResizeWindowGeometry(
@@ -91,14 +89,13 @@ public class DragResizeWindowGeometryTests {
EDGE_RESIZE_THICKNESS + 10, FINE_CORNER_SIZE, LARGE_CORNER_SIZE),
new DragResizeWindowGeometry(TASK_CORNER_RADIUS, TASK_SIZE,
EDGE_RESIZE_THICKNESS + 10, FINE_CORNER_SIZE, LARGE_CORNER_SIZE))
- .addEqualityGroup(new DragResizeWindowGeometry(TASK_CORNER_RADIUS, TASK_SIZE,
- EDGE_RESIZE_THICKNESS, FINE_CORNER_SIZE, LARGE_CORNER_SIZE + 5),
+ .addEqualityGroup(
new DragResizeWindowGeometry(TASK_CORNER_RADIUS, TASK_SIZE,
- EDGE_RESIZE_THICKNESS, FINE_CORNER_SIZE, LARGE_CORNER_SIZE + 5))
- .addEqualityGroup(new DragResizeWindowGeometry(TASK_CORNER_RADIUS, TASK_SIZE,
- EDGE_RESIZE_THICKNESS, FINE_CORNER_SIZE + 4, LARGE_CORNER_SIZE),
+ EDGE_RESIZE_THICKNESS + 10, FINE_CORNER_SIZE,
+ LARGE_CORNER_SIZE + 5),
new DragResizeWindowGeometry(TASK_CORNER_RADIUS, TASK_SIZE,
- EDGE_RESIZE_THICKNESS, FINE_CORNER_SIZE + 4, LARGE_CORNER_SIZE))
+ EDGE_RESIZE_THICKNESS + 10, FINE_CORNER_SIZE,
+ LARGE_CORNER_SIZE + 5))
.testEquals();
}
@@ -124,21 +121,21 @@ public class DragResizeWindowGeometryTests {
private static void verifyHorizontalEdge(@NonNull Region region, @NonNull Point point) {
assertThat(region.contains(point.x, point.y)).isTrue();
// Horizontally along the edge is still contained.
- assertThat(region.contains(point.x + EDGE_RESIZE_DEBUG_THICKNESS, point.y)).isTrue();
- assertThat(region.contains(point.x - EDGE_RESIZE_DEBUG_THICKNESS, point.y)).isTrue();
+ assertThat(region.contains(point.x + EDGE_RESIZE_THICKNESS, point.y)).isTrue();
+ assertThat(region.contains(point.x - EDGE_RESIZE_THICKNESS, point.y)).isTrue();
// Vertically along the edge is not contained.
- assertThat(region.contains(point.x, point.y - EDGE_RESIZE_DEBUG_THICKNESS)).isFalse();
- assertThat(region.contains(point.x, point.y + EDGE_RESIZE_DEBUG_THICKNESS)).isFalse();
+ assertThat(region.contains(point.x, point.y - EDGE_RESIZE_THICKNESS)).isFalse();
+ assertThat(region.contains(point.x, point.y + EDGE_RESIZE_THICKNESS)).isFalse();
}
private static void verifyVerticalEdge(@NonNull Region region, @NonNull Point point) {
assertThat(region.contains(point.x, point.y)).isTrue();
// Horizontally along the edge is not contained.
- assertThat(region.contains(point.x + EDGE_RESIZE_DEBUG_THICKNESS, point.y)).isFalse();
- assertThat(region.contains(point.x - EDGE_RESIZE_DEBUG_THICKNESS, point.y)).isFalse();
+ assertThat(region.contains(point.x + EDGE_RESIZE_THICKNESS, point.y)).isFalse();
+ assertThat(region.contains(point.x - EDGE_RESIZE_THICKNESS, point.y)).isFalse();
// Vertically along the edge is contained.
- assertThat(region.contains(point.x, point.y - EDGE_RESIZE_DEBUG_THICKNESS)).isTrue();
- assertThat(region.contains(point.x, point.y + EDGE_RESIZE_DEBUG_THICKNESS)).isTrue();
+ assertThat(region.contains(point.x, point.y - EDGE_RESIZE_THICKNESS)).isTrue();
+ assertThat(region.contains(point.x, point.y + EDGE_RESIZE_THICKNESS)).isTrue();
}
/**
@@ -151,10 +148,7 @@ public class DragResizeWindowGeometryTests {
public void testRegionUnion_edgeDragResizeEnabled_containsLargeCorners() {
Region region = new Region();
GEOMETRY.union(region);
- // Make sure we're choosing a point outside of any debug region buffer.
- final int cornerRadius = DragResizeWindowGeometry.DEBUG
- ? Math.max(LARGE_CORNER_SIZE / 2, EDGE_RESIZE_DEBUG_THICKNESS)
- : LARGE_CORNER_SIZE / 2;
+ final int cornerRadius = LARGE_CORNER_SIZE / 2;
new TestPoints(TASK_SIZE, cornerRadius).validateRegion(region);
}
@@ -168,9 +162,7 @@ public class DragResizeWindowGeometryTests {
public void testRegionUnion_edgeDragResizeDisabled_containsFineCorners() {
Region region = new Region();
GEOMETRY.union(region);
- final int cornerRadius = DragResizeWindowGeometry.DEBUG
- ? Math.max(LARGE_CORNER_SIZE / 2, EDGE_RESIZE_DEBUG_THICKNESS)
- : LARGE_CORNER_SIZE / 2;
+ final int cornerRadius = FINE_CORNER_SIZE / 2;
new TestPoints(TASK_SIZE, cornerRadius).validateRegion(region);
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/HandleMenuTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/HandleMenuTest.kt
index 0c50ab6b5008..adda9a688172 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/HandleMenuTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/HandleMenuTest.kt
@@ -22,10 +22,10 @@ import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN
import android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW
import android.graphics.Bitmap
import android.graphics.Color
+import android.graphics.Point
import android.graphics.Rect
-import android.platform.test.annotations.RequiresFlagsEnabled
-import android.platform.test.flag.junit.CheckFlagsRule
-import android.platform.test.flag.junit.DeviceFlagsValueProvider
+import android.platform.test.annotations.EnableFlags
+import android.platform.test.flag.junit.SetFlagsRule
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.Display
@@ -33,6 +33,7 @@ import android.view.LayoutInflater
import android.view.SurfaceControl
import android.view.SurfaceControlViewHost
import android.view.View
+import androidx.core.graphics.toPointF
import androidx.test.filters.SmallTest
import com.android.window.flags.Flags
import com.android.wm.shell.R
@@ -46,6 +47,7 @@ import com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UND
import com.android.wm.shell.splitscreen.SplitScreenController
import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalSystemViewContainer
import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalViewHostViewContainer
+import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Rule
@@ -69,7 +71,7 @@ import org.mockito.kotlin.whenever
class HandleMenuTest : ShellTestCase() {
@JvmField
@Rule
- val mCheckFlagsRule: CheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule()
+ val setFlagsRule: SetFlagsRule = SetFlagsRule()
@Mock
private lateinit var mockDesktopWindowDecoration: DesktopModeWindowDecoration
@@ -92,6 +94,8 @@ class HandleMenuTest : ShellTestCase() {
private lateinit var handleMenu: HandleMenu
+ private val menuWidthWithElevation = MENU_WIDTH + MENU_PILL_ELEVATION
+
@Before
fun setUp() {
val mockAdditionalViewHostViewContainer = AdditionalViewHostViewContainer(
@@ -100,7 +104,7 @@ class HandleMenuTest : ShellTestCase() {
) {
SurfaceControl.Transaction()
}
- val menuView = LayoutInflater.from(context).inflate(
+ val menuView = LayoutInflater.from(mContext).inflate(
R.layout.desktop_mode_window_decor_handle_menu, null)
whenever(mockDesktopWindowDecoration.addWindow(
anyInt(), any(), any(), any(), anyInt(), anyInt(), anyInt(), anyInt())
@@ -110,50 +114,69 @@ class HandleMenuTest : ShellTestCase() {
whenever(displayLayout.width()).thenReturn(DISPLAY_BOUNDS.width())
whenever(displayLayout.height()).thenReturn(DISPLAY_BOUNDS.height())
whenever(displayLayout.isLandscape).thenReturn(true)
- mockDesktopWindowDecoration.mDecorWindowContext = context
+ mContext.orCreateTestableResources.apply {
+ addOverride(R.dimen.desktop_mode_handle_menu_width, MENU_WIDTH)
+ addOverride(R.dimen.desktop_mode_handle_menu_height, MENU_HEIGHT)
+ addOverride(R.dimen.desktop_mode_handle_menu_margin_top, MENU_TOP_MARGIN)
+ addOverride(R.dimen.desktop_mode_handle_menu_margin_start, MENU_START_MARGIN)
+ addOverride(R.dimen.desktop_mode_handle_menu_pill_elevation, MENU_PILL_ELEVATION)
+ addOverride(
+ R.dimen.desktop_mode_handle_menu_pill_spacing_margin, MENU_PILL_SPACING_MARGIN)
+ }
+ mockDesktopWindowDecoration.mDecorWindowContext = mContext
}
@Test
- @RequiresFlagsEnabled(Flags.FLAG_ENABLE_ADDITIONAL_WINDOWS_ABOVE_STATUS_BAR)
+ @EnableFlags(Flags.FLAG_ENABLE_ADDITIONAL_WINDOWS_ABOVE_STATUS_BAR)
fun testFullscreenMenuUsesSystemViewContainer() {
createTaskInfo(WINDOWING_MODE_FULLSCREEN, SPLIT_POSITION_UNDEFINED)
val handleMenu = createAndShowHandleMenu()
- assertTrue(handleMenu.mHandleMenuViewContainer is AdditionalSystemViewContainer)
+ assertTrue(handleMenu.handleMenuViewContainer is AdditionalSystemViewContainer)
// Verify menu is created at coordinates that, when added to WindowManager,
// show at the top-center of display.
- assertTrue(handleMenu.mHandleMenuPosition.equals(16f, -512f))
+ val expected = Point(DISPLAY_BOUNDS.centerX() - menuWidthWithElevation / 2, MENU_TOP_MARGIN)
+ assertEquals(expected.toPointF(), handleMenu.handleMenuPosition)
}
@Test
- @RequiresFlagsEnabled(Flags.FLAG_ENABLE_ADDITIONAL_WINDOWS_ABOVE_STATUS_BAR)
+ @EnableFlags(Flags.FLAG_ENABLE_ADDITIONAL_WINDOWS_ABOVE_STATUS_BAR)
fun testFreeformMenu_usesViewHostViewContainer() {
createTaskInfo(WINDOWING_MODE_FREEFORM, SPLIT_POSITION_UNDEFINED)
handleMenu = createAndShowHandleMenu()
- assertTrue(handleMenu.mHandleMenuViewContainer is AdditionalViewHostViewContainer)
+ assertTrue(handleMenu.handleMenuViewContainer is AdditionalViewHostViewContainer)
// Verify menu is created near top-left of task.
- assertTrue(handleMenu.mHandleMenuPosition.equals(12f, 8f))
+ val expected = Point(MENU_START_MARGIN, MENU_TOP_MARGIN)
+ assertEquals(expected.toPointF(), handleMenu.handleMenuPosition)
}
@Test
- @RequiresFlagsEnabled(Flags.FLAG_ENABLE_ADDITIONAL_WINDOWS_ABOVE_STATUS_BAR)
+ @EnableFlags(Flags.FLAG_ENABLE_ADDITIONAL_WINDOWS_ABOVE_STATUS_BAR)
fun testSplitLeftMenu_usesSystemViewContainer() {
createTaskInfo(WINDOWING_MODE_MULTI_WINDOW, SPLIT_POSITION_TOP_OR_LEFT)
handleMenu = createAndShowHandleMenu()
- assertTrue(handleMenu.mHandleMenuViewContainer is AdditionalSystemViewContainer)
+ assertTrue(handleMenu.handleMenuViewContainer is AdditionalSystemViewContainer)
// Verify menu is created at coordinates that, when added to WindowManager,
- // show at the top of split left task.
- assertTrue(handleMenu.mHandleMenuPosition.equals(-624f, -512f))
+ // show at the top-center of split left task.
+ val expected = Point(
+ SPLIT_LEFT_BOUNDS.centerX() - menuWidthWithElevation / 2,
+ MENU_TOP_MARGIN
+ )
+ assertEquals(expected.toPointF(), handleMenu.handleMenuPosition)
}
@Test
- @RequiresFlagsEnabled(Flags.FLAG_ENABLE_ADDITIONAL_WINDOWS_ABOVE_STATUS_BAR)
+ @EnableFlags(Flags.FLAG_ENABLE_ADDITIONAL_WINDOWS_ABOVE_STATUS_BAR)
fun testSplitRightMenu_usesSystemViewContainer() {
createTaskInfo(WINDOWING_MODE_MULTI_WINDOW, SPLIT_POSITION_BOTTOM_OR_RIGHT)
handleMenu = createAndShowHandleMenu()
- assertTrue(handleMenu.mHandleMenuViewContainer is AdditionalSystemViewContainer)
+ assertTrue(handleMenu.handleMenuViewContainer is AdditionalSystemViewContainer)
// Verify menu is created at coordinates that, when added to WindowManager,
- // show at the top of split right task.
- assertTrue(handleMenu.mHandleMenuPosition.equals(656f, -512f))
+ // show at the top-center of split right task.
+ val expected = Point(
+ SPLIT_RIGHT_BOUNDS.centerX() - menuWidthWithElevation / 2,
+ MENU_TOP_MARGIN
+ )
+ assertEquals(expected.toPointF(), handleMenu.handleMenuPosition)
}
private fun createTaskInfo(windowingMode: Int, splitPosition: Int) {
@@ -178,14 +201,10 @@ class HandleMenuTest : ShellTestCase() {
.setBounds(bounds)
.setVisible(true)
.build()
- // Calculate captionX similar to how WindowDecoration calculates it.
- whenever(mockDesktopWindowDecoration.captionX).thenReturn(
- (mockDesktopWindowDecoration.mTaskInfo.configuration.windowConfiguration
- .bounds.width() - context.resources.getDimensionPixelSize(
- R.dimen.desktop_mode_fullscreen_decor_caption_width)) / 2)
whenever(splitScreenController.getSplitPosition(any())).thenReturn(splitPosition)
whenever(splitScreenController.getStageBounds(any(), any())).thenAnswer {
(it.arguments.first() as Rect).set(SPLIT_LEFT_BOUNDS)
+ (it.arguments[1] as Rect).set(SPLIT_RIGHT_BOUNDS)
}
}
@@ -193,7 +212,7 @@ class HandleMenuTest : ShellTestCase() {
val layoutId = if (mockDesktopWindowDecoration.mTaskInfo.isFreeform) {
R.layout.desktop_mode_app_header
} else {
- R.layout.desktop_mode_app_header
+ R.layout.desktop_mode_app_handle
}
val handleMenu = HandleMenu(mockDesktopWindowDecoration, layoutId,
onClickListener, onTouchListener, appIcon, appName, displayController,
@@ -208,5 +227,11 @@ class HandleMenuTest : ShellTestCase() {
private val FREEFORM_BOUNDS = Rect(500, 500, 2000, 1200)
private val SPLIT_LEFT_BOUNDS = Rect(0, 0, 1280, 1600)
private val SPLIT_RIGHT_BOUNDS = Rect(1280, 0, 2560, 1600)
+ private const val MENU_WIDTH = 200
+ private const val MENU_HEIGHT = 400
+ private const val MENU_TOP_MARGIN = 10
+ private const val MENU_START_MARGIN = 20
+ private const val MENU_PILL_ELEVATION = 2
+ private const val MENU_PILL_SPACING_MARGIN = 4
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
index 31c6479195c3..2d1bf14ffbb3 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
@@ -18,6 +18,8 @@ package com.android.wm.shell.windowdecor;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT;
+import static android.view.InsetsSource.FLAG_FORCE_CONSUMING;
import static android.view.WindowInsets.Type.captionBar;
import static android.view.WindowInsets.Type.mandatorySystemGestures;
import static android.view.WindowInsets.Type.statusBars;
@@ -54,6 +56,8 @@ import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.Point;
import android.graphics.Rect;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.testing.AndroidTestingRunner;
import android.util.DisplayMetrics;
import android.view.AttachedSurfaceControl;
@@ -71,6 +75,7 @@ import android.window.WindowContainerTransaction;
import androidx.test.filters.SmallTest;
import com.android.dx.mockito.inline.extended.StaticMockitoSession;
+import com.android.window.flags.Flags;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.TestRunningTaskInfoBuilder;
@@ -80,6 +85,7 @@ import com.android.wm.shell.tests.R;
import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalViewContainer;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -105,6 +111,9 @@ public class WindowDecorationTests extends ShellTestCase {
private static final int CORNER_RADIUS = 20;
private static final int STATUS_BAR_INSET_SOURCE_ID = 0;
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(DEVICE_DEFAULT);
+
private final WindowDecoration.RelayoutResult<TestView> mRelayoutResult =
new WindowDecoration.RelayoutResult<>();
@@ -260,7 +269,8 @@ public class WindowDecorationTests extends ShellTestCase {
eq(0 /* index */),
eq(WindowInsets.Type.captionBar()),
eq(new Rect(100, 300, 400, 364)),
- any());
+ any(),
+ anyInt());
verify(mMockSurfaceControlStartT).setCornerRadius(mMockTaskSurface, CORNER_RADIUS);
verify(mMockSurfaceControlFinishT).setCornerRadius(mMockTaskSurface, CORNER_RADIUS);
@@ -565,9 +575,9 @@ public class WindowDecorationTests extends ShellTestCase {
windowDecor.relayout(taskInfo);
verify(mMockWindowContainerTransaction).addInsetsSource(eq(taskInfo.token), any(),
- eq(0) /* index */, eq(captionBar()), any(), any());
+ eq(0) /* index */, eq(captionBar()), any(), any(), anyInt());
verify(mMockWindowContainerTransaction).addInsetsSource(eq(taskInfo.token), any(),
- eq(0) /* index */, eq(mandatorySystemGestures()), any(), any());
+ eq(0) /* index */, eq(mandatorySystemGestures()), any(), any(), anyInt());
}
@Test
@@ -654,9 +664,9 @@ public class WindowDecorationTests extends ShellTestCase {
// Never added.
verify(mMockWindowContainerTransaction, never()).addInsetsSource(eq(taskInfo.token), any(),
- eq(0) /* index */, eq(captionBar()), any(), any());
+ eq(0) /* index */, eq(captionBar()), any(), any(), anyInt());
verify(mMockWindowContainerTransaction, never()).addInsetsSource(eq(taskInfo.token), any(),
- eq(0) /* index */, eq(mandatorySystemGestures()), any(), any());
+ eq(0) /* index */, eq(mandatorySystemGestures()), any(), any(), anyInt());
// No need to remove them if they were never added.
verify(mMockWindowContainerTransaction, never()).removeInsetsSource(eq(taskInfo.token),
any(), eq(0) /* index */, eq(captionBar()));
@@ -681,9 +691,9 @@ public class WindowDecorationTests extends ShellTestCase {
mInsetsState.getOrCreateSource(STATUS_BAR_INSET_SOURCE_ID, captionBar()).setVisible(true);
windowDecor.relayout(taskInfo);
verify(mMockWindowContainerTransaction).addInsetsSource(eq(taskInfo.token), any(),
- eq(0) /* index */, eq(captionBar()), any(), any());
+ eq(0) /* index */, eq(captionBar()), any(), any(), anyInt());
verify(mMockWindowContainerTransaction).addInsetsSource(eq(taskInfo.token), any(),
- eq(0) /* index */, eq(mandatorySystemGestures()), any(), any());
+ eq(0) /* index */, eq(mandatorySystemGestures()), any(), any(), anyInt());
windowDecor.close();
@@ -738,9 +748,9 @@ public class WindowDecorationTests extends ShellTestCase {
// Insets should be applied twice.
verify(mMockWindowContainerTransaction, times(2)).addInsetsSource(eq(token), any(),
- eq(0) /* index */, eq(captionBar()), any(), any());
+ eq(0) /* index */, eq(captionBar()), any(), any(), anyInt());
verify(mMockWindowContainerTransaction, times(2)).addInsetsSource(eq(token), any(),
- eq(0) /* index */, eq(mandatorySystemGestures()), any(), any());
+ eq(0) /* index */, eq(mandatorySystemGestures()), any(), any(), anyInt());
}
@Test
@@ -765,9 +775,30 @@ public class WindowDecorationTests extends ShellTestCase {
// Insets should only need to be applied once.
verify(mMockWindowContainerTransaction, times(1)).addInsetsSource(eq(token), any(),
- eq(0) /* index */, eq(captionBar()), any(), any());
+ eq(0) /* index */, eq(captionBar()), any(), any(), anyInt());
verify(mMockWindowContainerTransaction, times(1)).addInsetsSource(eq(token), any(),
- eq(0) /* index */, eq(mandatorySystemGestures()), any(), any());
+ eq(0) /* index */, eq(mandatorySystemGestures()), any(), any(), anyInt());
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION)
+ public void testRelayout_captionInsetForceConsume() {
+ final Display defaultDisplay = mock(Display.class);
+ doReturn(defaultDisplay).when(mMockDisplayController)
+ .getDisplay(Display.DEFAULT_DISPLAY);
+ final WindowContainerToken token = TestRunningTaskInfoBuilder.createMockWCToken();
+ final TestRunningTaskInfoBuilder builder = new TestRunningTaskInfoBuilder()
+ .setDisplayId(Display.DEFAULT_DISPLAY)
+ .setVisible(true);
+
+ final ActivityManager.RunningTaskInfo taskInfo =
+ builder.setToken(token).setBounds(new Rect(0, 0, 1000, 1000)).build();
+ final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo);
+ windowDecor.relayout(taskInfo);
+
+ // Caption inset source should be force-consuming.
+ verify(mMockWindowContainerTransaction).addInsetsSource(eq(token), any(),
+ eq(0) /* index */, eq(captionBar()), any(), any(), eq(FLAG_FORCE_CONSUMING));
}
@Test
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 341599e79662..e302fa8b1fc3 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -114,16 +114,12 @@ cc_defaults {
"libbase",
"libharfbuzz_ng",
"libminikin",
- "server_configurable_flags",
- "libaconfig_storage_read_api_cc"
],
static_libs: [
"libui-types",
],
- whole_static_libs: ["hwui_flags_cc_lib"],
-
target: {
android: {
shared_libs: [
@@ -145,6 +141,8 @@ cc_defaults {
"libsync",
"libui",
"aconfig_text_flags_c_lib",
+ "server_configurable_flags",
+ "libaconfig_storage_read_api_cc",
],
static_libs: [
"libEGL_blobCache",
@@ -155,6 +153,7 @@ cc_defaults {
"libstatssocket_lazy",
"libtonemap",
],
+ whole_static_libs: ["hwui_flags_cc_lib"],
},
host: {
static_libs: [
@@ -419,7 +418,6 @@ cc_defaults {
],
static_libs: [
- "libnativehelper_lazy",
"libziparchive_for_incfs",
],
@@ -446,6 +444,7 @@ cc_defaults {
],
static_libs: [
"libgif",
+ "libnativehelper_lazy",
"libstatslog_hwui",
"libstatspull_lazy",
"libstatssocket_lazy",
@@ -464,6 +463,7 @@ cc_defaults {
],
static_libs: [
"libandroidfw",
+ "libnativehelper_jvm",
],
},
},
diff --git a/libs/hwui/apex/LayoutlibLoader.cpp b/libs/hwui/apex/LayoutlibLoader.cpp
index 70a9ef04d6f3..b4e6b7243ddc 100644
--- a/libs/hwui/apex/LayoutlibLoader.cpp
+++ b/libs/hwui/apex/LayoutlibLoader.cpp
@@ -28,6 +28,7 @@ using namespace std;
extern int register_android_graphics_Bitmap(JNIEnv*);
extern int register_android_graphics_BitmapFactory(JNIEnv*);
+extern int register_android_graphics_BitmapRegionDecoder(JNIEnv*);
extern int register_android_graphics_ByteBufferStreamAdaptor(JNIEnv* env);
extern int register_android_graphics_Camera(JNIEnv* env);
extern int register_android_graphics_CreateJavaOutputStreamAdaptor(JNIEnv* env);
@@ -41,6 +42,7 @@ extern int register_android_graphics_Shader(JNIEnv* env);
extern int register_android_graphics_RenderEffect(JNIEnv* env);
extern int register_android_graphics_Typeface(JNIEnv* env);
extern int register_android_graphics_YuvImage(JNIEnv* env);
+extern int register_android_graphics_drawable_AnimatedImageDrawable(JNIEnv* env);
namespace android {
@@ -51,7 +53,12 @@ extern int register_android_graphics_ColorFilter(JNIEnv* env);
extern int register_android_graphics_ColorSpace(JNIEnv* env);
extern int register_android_graphics_DrawFilter(JNIEnv* env);
extern int register_android_graphics_FontFamily(JNIEnv* env);
+extern int register_android_graphics_Gainmap(JNIEnv* env);
+extern int register_android_graphics_HardwareBufferRenderer(JNIEnv* env);
+extern int register_android_graphics_HardwareRendererObserver(JNIEnv* env);
extern int register_android_graphics_Matrix(JNIEnv* env);
+extern int register_android_graphics_Mesh(JNIEnv* env);
+extern int register_android_graphics_MeshSpecification(JNIEnv* env);
extern int register_android_graphics_Paint(JNIEnv* env);
extern int register_android_graphics_Path(JNIEnv* env);
extern int register_android_graphics_PathIterator(JNIEnv* env);
@@ -72,6 +79,7 @@ extern int register_android_graphics_text_GraphemeBreak(JNIEnv* env);
extern int register_android_util_PathParser(JNIEnv* env);
extern int register_android_view_DisplayListCanvas(JNIEnv* env);
extern int register_android_view_RenderNode(JNIEnv* env);
+extern int register_android_view_ThreadedRenderer(JNIEnv* env);
#define REG_JNI(name) { name }
struct RegJNIRec {
@@ -83,6 +91,8 @@ struct RegJNIRec {
static const std::unordered_map<std::string, RegJNIRec> gRegJNIMap = {
{"android.graphics.Bitmap", REG_JNI(register_android_graphics_Bitmap)},
{"android.graphics.BitmapFactory", REG_JNI(register_android_graphics_BitmapFactory)},
+ {"android.graphics.BitmapRegionDecoder",
+ REG_JNI(register_android_graphics_BitmapRegionDecoder)},
{"android.graphics.ByteBufferStreamAdaptor",
REG_JNI(register_android_graphics_ByteBufferStreamAdaptor)},
{"android.graphics.Camera", REG_JNI(register_android_graphics_Camera)},
@@ -95,11 +105,20 @@ static const std::unordered_map<std::string, RegJNIRec> gRegJNIMap = {
REG_JNI(register_android_graphics_CreateJavaOutputStreamAdaptor)},
{"android.graphics.DrawFilter", REG_JNI(register_android_graphics_DrawFilter)},
{"android.graphics.FontFamily", REG_JNI(register_android_graphics_FontFamily)},
+ {"android.graphics.Gainmap", REG_JNI(register_android_graphics_Gainmap)},
{"android.graphics.Graphics", REG_JNI(register_android_graphics_Graphics)},
+ {"android.graphics.HardwareBufferRenderer",
+ REG_JNI(register_android_graphics_HardwareBufferRenderer)},
+ {"android.graphics.HardwareRenderer", REG_JNI(register_android_view_ThreadedRenderer)},
+ {"android.graphics.HardwareRendererObserver",
+ REG_JNI(register_android_graphics_HardwareRendererObserver)},
{"android.graphics.ImageDecoder", REG_JNI(register_android_graphics_ImageDecoder)},
{"android.graphics.Interpolator", REG_JNI(register_android_graphics_Interpolator)},
{"android.graphics.MaskFilter", REG_JNI(register_android_graphics_MaskFilter)},
{"android.graphics.Matrix", REG_JNI(register_android_graphics_Matrix)},
+ {"android.graphics.Mesh", REG_JNI(register_android_graphics_Mesh)},
+ {"android.graphics.MeshSpecification",
+ REG_JNI(register_android_graphics_MeshSpecification)},
{"android.graphics.NinePatch", REG_JNI(register_android_graphics_NinePatch)},
{"android.graphics.Paint", REG_JNI(register_android_graphics_Paint)},
{"android.graphics.Path", REG_JNI(register_android_graphics_Path)},
@@ -118,6 +137,8 @@ static const std::unordered_map<std::string, RegJNIRec> gRegJNIMap = {
REG_JNI(register_android_graphics_animation_NativeInterpolatorFactory)},
{"android.graphics.animation.RenderNodeAnimator",
REG_JNI(register_android_graphics_animation_RenderNodeAnimator)},
+ {"android.graphics.drawable.AnimatedImageDrawable",
+ REG_JNI(register_android_graphics_drawable_AnimatedImageDrawable)},
{"android.graphics.drawable.AnimatedVectorDrawable",
REG_JNI(register_android_graphics_drawable_AnimatedVectorDrawable)},
{"android.graphics.drawable.VectorDrawable",
diff --git a/libs/hwui/hwui/DrawTextFunctor.h b/libs/hwui/hwui/DrawTextFunctor.h
index cfca48084d97..0efb2c81af01 100644
--- a/libs/hwui/hwui/DrawTextFunctor.h
+++ b/libs/hwui/hwui/DrawTextFunctor.h
@@ -17,7 +17,6 @@
#include <SkFontMetrics.h>
#include <SkRRect.h>
#include <SkTextBlob.h>
-#include <com_android_graphics_hwui_flags.h>
#include "../utils/Color.h"
#include "Canvas.h"
@@ -30,7 +29,19 @@
#include "hwui/PaintFilter.h"
#include "pipeline/skia/SkiaRecordingCanvas.h"
+#ifdef __ANDROID__
+#include <com_android_graphics_hwui_flags.h>
namespace flags = com::android::graphics::hwui::flags;
+#else
+namespace flags {
+constexpr bool high_contrast_text_luminance() {
+ return false;
+}
+constexpr bool high_contrast_text_small_text_rect() {
+ return false;
+}
+} // namespace flags
+#endif
namespace android {
diff --git a/libs/hwui/jni/MeshSpecification.cpp b/libs/hwui/jni/MeshSpecification.cpp
index ae9792df3d82..b943496ae9f7 100644
--- a/libs/hwui/jni/MeshSpecification.cpp
+++ b/libs/hwui/jni/MeshSpecification.cpp
@@ -126,7 +126,7 @@ static void MeshSpecification_safeUnref(SkMeshSpecification* meshSpec) {
SkSafeUnref(meshSpec);
}
-static jlong getMeshSpecificationFinalizer() {
+static jlong getMeshSpecificationFinalizer(CRITICAL_JNI_PARAMS) {
return static_cast<jlong>(reinterpret_cast<uintptr_t>(&MeshSpecification_safeUnref));
}
diff --git a/libs/hwui/jni/android_graphics_HardwareBufferRenderer.cpp b/libs/hwui/jni/android_graphics_HardwareBufferRenderer.cpp
index e3cdee6e7034..3b1b86160f3a 100644
--- a/libs/hwui/jni/android_graphics_HardwareBufferRenderer.cpp
+++ b/libs/hwui/jni/android_graphics_HardwareBufferRenderer.cpp
@@ -135,7 +135,7 @@ static void android_graphics_HardwareBufferRenderer_setLightAlpha(JNIEnv* env, j
proxy->setLightAlpha((uint8_t)(255 * ambientShadowAlpha), (uint8_t)(255 * spotShadowAlpha));
}
-static jlong android_graphics_HardwareBufferRenderer_getFinalizer() {
+static jlong android_graphics_HardwareBufferRenderer_getFinalizer(CRITICAL_JNI_PARAMS) {
return static_cast<jlong>(reinterpret_cast<uintptr_t>(&HardwareBufferRenderer_destroy));
}
diff --git a/location/Android.bp b/location/Android.bp
index c0e102acad4d..bc02d1f852de 100644
--- a/location/Android.bp
+++ b/location/Android.bp
@@ -30,9 +30,6 @@ java_sdk_library {
"app-compat-annotations",
"unsupportedappusage", // for android.compat.annotation.UnsupportedAppUsage
],
- hidden_api_packages: [
- "com.android.internal.location",
- ],
aidl: {
include_dirs: [
"frameworks/base/location/java",
diff --git a/location/java/com/android/internal/location/package-info.java b/location/java/com/android/internal/location/package-info.java
new file mode 100644
index 000000000000..25573c15ce59
--- /dev/null
+++ b/location/java/com/android/internal/location/package-info.java
@@ -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.
+ */
+
+/**
+ * Exclude from API surfaces
+ *
+ * @hide
+ */
+package com.android.internal.location;
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 73deb17d0055..03cd53580b1b 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -1797,6 +1797,7 @@ public class AudioTrack extends PlayerBase
(flags != 0 // cannot have any special flags
|| attributes.getUsage() != AudioAttributes.USAGE_MEDIA
|| (attributes.getContentType() != AudioAttributes.CONTENT_TYPE_UNKNOWN
+ && attributes.getContentType() != AudioAttributes.CONTENT_TYPE_SPEECH
&& attributes.getContentType() != AudioAttributes.CONTENT_TYPE_MUSIC
&& attributes.getContentType() != AudioAttributes.CONTENT_TYPE_MOVIE))) {
return false;
diff --git a/media/tests/mediatestutils/java/com/android/media/mediatestutils/TestUtils.java b/media/tests/mediatestutils/java/com/android/media/mediatestutils/TestUtils.java
index 7065e3a8f68a..46c72730cf5b 100644
--- a/media/tests/mediatestutils/java/com/android/media/mediatestutils/TestUtils.java
+++ b/media/tests/mediatestutils/java/com/android/media/mediatestutils/TestUtils.java
@@ -27,6 +27,7 @@ import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import java.lang.ref.WeakReference;
+import java.util.Collection;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Function;
@@ -35,12 +36,13 @@ import java.util.function.Predicate;
/** Utils for audio tests. */
public class TestUtils {
/**
- * Return a future for an intent delivered by a broadcast receiver which matches an
- * action and predicate.
+ * Return a future for an intent delivered by a broadcast receiver which matches an action and
+ * predicate.
+ *
* @param context - Context to register the receiver with
* @param action - String representing action to register receiver for
- * @param pred - Predicate which sets the future if evaluates to true, otherwise, leaves
- * the future unset. If the predicate throws, the future is set exceptionally
+ * @param pred - Predicate which sets the future if evaluates to true, otherwise, leaves the
+ * future unset. If the predicate throws, the future is set exceptionally
* @return - The future representing intent delivery matching predicate.
*/
public static ListenableFuture<Intent> getFutureForIntent(
@@ -76,20 +78,77 @@ public class TestUtils {
}
/**
- * Same as previous, but with no predicate.
+ * Return a future for an intent delivered by a broadcast receiver which matches one of a set of
+ * actions and predicate.
+ *
+ * @param context - Context to register the receiver with
+ * @param actionsCollection - Collection of actions which to listen for, completing on any
+ * @param pred - Predicate which sets the future if evaluates to true, otherwise, leaves the
+ * future unset. If the predicate throws, the future is set exceptionally
+ * @return - The future representing intent delivery matching predicate.
*/
+ public static ListenableFuture<Intent> getFutureForIntent(
+ Context context, Collection<String> actionsCollection, Predicate<Intent> pred) {
+ // These are evaluated async
+ Objects.requireNonNull(actionsCollection);
+ Objects.requireNonNull(pred);
+ if (actionsCollection.isEmpty()) {
+ throw new IllegalArgumentException("actionsCollection must not be empty");
+ }
+ return getFutureForListener(
+ (recv) ->
+ context.registerReceiver(
+ recv,
+ actionsCollection.stream()
+ .reduce(
+ new IntentFilter(),
+ (IntentFilter filter, String x) -> {
+ filter.addAction(x);
+ return filter;
+ },
+ (x, y) -> {
+ throw new IllegalStateException(
+ "No parallel support");
+ }),
+ Context.RECEIVER_EXPORTED),
+ (recv) -> {
+ try {
+ context.unregisterReceiver(recv);
+ } catch (IllegalArgumentException e) {
+ // Thrown when receiver is already unregistered, nothing to do
+ }
+ },
+ (completer) ->
+ new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ try {
+ if (actionsCollection.contains(intent.getAction())
+ && pred.test(intent)) {
+ completer.set(intent);
+ }
+ } catch (Exception e) {
+ completer.setException(e);
+ }
+ }
+ },
+ "Intent receiver future for actions: " + actionsCollection);
+ }
+
+ /** Same as previous, but with no predicate. */
public static ListenableFuture<Intent> getFutureForIntent(Context context, String action) {
return getFutureForIntent(context, action, i -> true);
}
/**
* Return a future for a callback registered to a listener interface.
+ *
* @param registerFunc - Function which consumes the callback object for registration
- * @param unregisterFunc - Function which consumes the callback object for unregistration
- * This function is called when the future is completed or cancelled
+ * @param unregisterFunc - Function which consumes the callback object for unregistration This
+ * function is called when the future is completed or cancelled
* @param instantiateCallback - Factory function for the callback object, provided a completer
- * object (see {@code CallbackToFutureAdapter.Completer<T>}), which is a logical reference
- * to the future returned by this function
+ * object (see {@code CallbackToFutureAdapter.Completer<T>}), which is a logical reference
+ * to the future returned by this function
* @param debug - Debug string contained in future {@code toString} representation.
*/
public static <T, V> ListenableFuture<T> getFutureForListener(
diff --git a/nfc/Android.bp b/nfc/Android.bp
index 13ac2311bde3..0282e6f5c246 100644
--- a/nfc/Android.bp
+++ b/nfc/Android.bp
@@ -61,9 +61,6 @@ java_sdk_library {
"android.nfc",
"com.android.nfc",
],
- hidden_api_packages: [
- "com.android.nfc",
- ],
impl_library_visibility: [
"//frameworks/base:__subpackages__",
"//cts/hostsidetests/multidevices/nfc:__subpackages__",
diff --git a/nfc/java/android/nfc/INfcAdapter.aidl b/nfc/java/android/nfc/INfcAdapter.aidl
index fd77820afc81..90ca92f299a4 100644
--- a/nfc/java/android/nfc/INfcAdapter.aidl
+++ b/nfc/java/android/nfc/INfcAdapter.aidl
@@ -104,6 +104,7 @@ interface INfcAdapter
void notifyPollingLoop(in PollingFrame frame);
void notifyHceDeactivated();
+ void notifyTestHceData(in int technology, in byte[] data);
int sendVendorNciMessage(int mt, int gid, int oid, in byte[] payload);
void registerVendorExtensionCallback(in INfcVendorNciCallback callbacks);
void unregisterVendorExtensionCallback(in INfcVendorNciCallback callbacks);
diff --git a/nfc/java/android/nfc/NfcAdapter.java b/nfc/java/android/nfc/NfcAdapter.java
index 1dfc81e2108e..395f81d73351 100644
--- a/nfc/java/android/nfc/NfcAdapter.java
+++ b/nfc/java/android/nfc/NfcAdapter.java
@@ -963,22 +963,9 @@ public final class NfcAdapter {
throw new UnsupportedOperationException("You need a context on NfcAdapter to use the "
+ " NFC extras APIs");
}
- try {
- return sService.getNfcDtaInterface(mContext.getPackageName());
- } catch (RemoteException e) {
- attemptDeadServiceRecovery(e);
- // Try one more time
- if (sService == null) {
- Log.e(TAG, "Failed to recover NFC Service.");
- return null;
- }
- try {
- return sService.getNfcDtaInterface(mContext.getPackageName());
- } catch (RemoteException ee) {
- Log.e(TAG, "Failed to recover NFC Service.");
- }
- return null;
- }
+ return callServiceReturn(() -> sService.getNfcDtaInterface(mContext.getPackageName()),
+ null);
+
}
/**
@@ -1095,22 +1082,8 @@ public final class NfcAdapter {
@SystemApi
@FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
public @AdapterState int getAdapterState() {
- try {
- return sService.getState();
- } catch (RemoteException e) {
- attemptDeadServiceRecovery(e);
- // Try one more time
- if (sService == null) {
- Log.e(TAG, "Failed to recover NFC Service.");
- return NfcAdapter.STATE_OFF;
- }
- try {
- return sService.getState();
- } catch (RemoteException ee) {
- Log.e(TAG, "Failed to recover NFC Service.");
- }
- return NfcAdapter.STATE_OFF;
- }
+ return callServiceReturn(() -> sService.getState(), NfcAdapter.STATE_OFF);
+
}
/**
@@ -1134,22 +1107,8 @@ public final class NfcAdapter {
@FlaggedApi(Flags.FLAG_NFC_STATE_CHANGE)
@RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
public boolean enable() {
- try {
- return sService.enable(mContext.getPackageName());
- } catch (RemoteException e) {
- attemptDeadServiceRecovery(e);
- // Try one more time
- if (sService == null) {
- Log.e(TAG, "Failed to recover NFC Service.");
- return false;
- }
- try {
- return sService.enable(mContext.getPackageName());
- } catch (RemoteException ee) {
- Log.e(TAG, "Failed to recover NFC Service.");
- }
- return false;
- }
+ return callServiceReturn(() -> sService.enable(mContext.getPackageName()), false);
+
}
/**
@@ -1175,22 +1134,9 @@ public final class NfcAdapter {
@FlaggedApi(Flags.FLAG_NFC_STATE_CHANGE)
@RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
public boolean disable() {
- try {
- return sService.disable(true, mContext.getPackageName());
- } catch (RemoteException e) {
- attemptDeadServiceRecovery(e);
- // Try one more time
- if (sService == null) {
- Log.e(TAG, "Failed to recover NFC Service.");
- return false;
- }
- try {
- return sService.disable(true, mContext.getPackageName());
- } catch (RemoteException ee) {
- Log.e(TAG, "Failed to recover NFC Service.");
- }
- return false;
- }
+ return callServiceReturn(() -> sService.disable(true, mContext.getPackageName()),
+ false);
+
}
/**
@@ -1200,22 +1146,9 @@ public final class NfcAdapter {
@SystemApi
@RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
public boolean disable(boolean persist) {
- try {
- return sService.disable(persist, mContext.getPackageName());
- } catch (RemoteException e) {
- attemptDeadServiceRecovery(e);
- // Try one more time
- if (sService == null) {
- Log.e(TAG, "Failed to recover NFC Service.");
- return false;
- }
- try {
- return sService.disable(persist, mContext.getPackageName());
- } catch (RemoteException ee) {
- Log.e(TAG, "Failed to recover NFC Service.");
- }
- return false;
- }
+ return callServiceReturn(() -> sService.disable(persist, mContext.getPackageName()),
+ false);
+
}
/**
@@ -1241,12 +1174,7 @@ public final class NfcAdapter {
*/
@FlaggedApi(Flags.FLAG_NFC_OBSERVE_MODE)
public boolean isObserveModeSupported() {
- try {
- return sService.isObserveModeSupported();
- } catch (RemoteException e) {
- attemptDeadServiceRecovery(e);
- return false;
- }
+ return callServiceReturn(() -> sService.isObserveModeSupported(), false);
}
/**
@@ -1257,12 +1185,7 @@ public final class NfcAdapter {
@FlaggedApi(Flags.FLAG_NFC_OBSERVE_MODE)
public boolean isObserveModeEnabled() {
- try {
- return sService.isObserveModeEnabled();
- } catch (RemoteException e) {
- attemptDeadServiceRecovery(e);
- return false;
- }
+ return callServiceReturn(() -> sService.isObserveModeEnabled(), false);
}
/**
@@ -1286,12 +1209,8 @@ public final class NfcAdapter {
throw new UnsupportedOperationException("You need a context on NfcAdapter to use the "
+ " observe mode APIs");
}
- try {
- return sService.setObserveMode(enabled, mContext.getPackageName());
- } catch (RemoteException e) {
- attemptDeadServiceRecovery(e);
- return false;
- }
+ return callServiceReturn(() -> sService.setObserveMode(enabled, mContext.getPackageName()),
+ false);
}
/**
@@ -2057,22 +1976,8 @@ public final class NfcAdapter {
if (!sHasNfcFeature && !sHasCeFeature) {
throw new UnsupportedOperationException();
}
- try {
- return sService.setNfcSecure(enable);
- } catch (RemoteException e) {
- attemptDeadServiceRecovery(e);
- // Try one more time
- if (sService == null) {
- Log.e(TAG, "Failed to recover NFC Service.");
- return false;
- }
- try {
- return sService.setNfcSecure(enable);
- } catch (RemoteException ee) {
- Log.e(TAG, "Failed to recover NFC Service.");
- }
- return false;
- }
+ return callServiceReturn(() -> sService.setNfcSecure(enable), false);
+
}
/**
@@ -2088,22 +1993,8 @@ public final class NfcAdapter {
if (!sHasNfcFeature && !sHasCeFeature) {
throw new UnsupportedOperationException();
}
- try {
- return sService.deviceSupportsNfcSecure();
- } catch (RemoteException e) {
- attemptDeadServiceRecovery(e);
- // Try one more time
- if (sService == null) {
- Log.e(TAG, "Failed to recover NFC Service.");
- return false;
- }
- try {
- return sService.deviceSupportsNfcSecure();
- } catch (RemoteException ee) {
- Log.e(TAG, "Failed to recover NFC Service.");
- }
- return false;
- }
+ return callServiceReturn(() -> sService.deviceSupportsNfcSecure(), false);
+
}
/**
@@ -2121,22 +2012,8 @@ public final class NfcAdapter {
if (!sHasNfcFeature && !sHasCeFeature) {
throw new UnsupportedOperationException();
}
- try {
- return sService.getNfcAntennaInfo();
- } catch (RemoteException e) {
- attemptDeadServiceRecovery(e);
- // Try one more time
- if (sService == null) {
- Log.e(TAG, "Failed to recover NFC Service.");
- return null;
- }
- try {
- return sService.getNfcAntennaInfo();
- } catch (RemoteException ee) {
- Log.e(TAG, "Failed to recover NFC Service.");
- }
- return null;
- }
+ return callServiceReturn(() -> sService.getNfcAntennaInfo(), null);
+
}
/**
@@ -2154,22 +2031,8 @@ public final class NfcAdapter {
if (!sHasNfcFeature && !sHasCeFeature) {
throw new UnsupportedOperationException();
}
- try {
- return sService.isNfcSecureEnabled();
- } catch (RemoteException e) {
- attemptDeadServiceRecovery(e);
- // Try one more time
- if (sService == null) {
- Log.e(TAG, "Failed to recover NFC Service.");
- return false;
- }
- try {
- return sService.isNfcSecureEnabled();
- } catch (RemoteException ee) {
- Log.e(TAG, "Failed to recover NFC Service.");
- }
- return false;
- }
+ return callServiceReturn(() -> sService.isNfcSecureEnabled(), false);
+
}
/**
@@ -2185,22 +2048,8 @@ public final class NfcAdapter {
if (!sHasNfcFeature) {
throw new UnsupportedOperationException();
}
- try {
- return sService.enableReaderOption(enable);
- } catch (RemoteException e) {
- attemptDeadServiceRecovery(e);
- // Try one more time
- if (sService == null) {
- Log.e(TAG, "Failed to recover NFC Service.");
- return false;
- }
- try {
- return sService.enableReaderOption(enable);
- } catch (RemoteException ee) {
- Log.e(TAG, "Failed to recover NFC Service.");
- }
- return false;
- }
+ return callServiceReturn(() -> sService.enableReaderOption(enable), false);
+
}
/**
@@ -2214,22 +2063,8 @@ public final class NfcAdapter {
if (!sHasNfcFeature) {
throw new UnsupportedOperationException();
}
- try {
- return sService.isReaderOptionSupported();
- } catch (RemoteException e) {
- attemptDeadServiceRecovery(e);
- // Try one more time
- if (sService == null) {
- Log.e(TAG, "Failed to recover NFC Service.");
- return false;
- }
- try {
- return sService.isReaderOptionSupported();
- } catch (RemoteException ee) {
- Log.e(TAG, "Failed to recover NFC Service.");
- }
- return false;
- }
+ return callServiceReturn(() -> sService.isReaderOptionSupported(), false);
+
}
/**
@@ -2245,22 +2080,8 @@ public final class NfcAdapter {
if (!sHasNfcFeature) {
throw new UnsupportedOperationException();
}
- try {
- return sService.isReaderOptionEnabled();
- } catch (RemoteException e) {
- attemptDeadServiceRecovery(e);
- // Try one more time
- if (sService == null) {
- Log.e(TAG, "Failed to recover NFC Service.");
- return false;
- }
- try {
- return sService.isReaderOptionEnabled();
- } catch (RemoteException ee) {
- Log.e(TAG, "Failed to recover NFC Service.");
- }
- return false;
- }
+ return callServiceReturn(() -> sService.isReaderOptionEnabled(), false);
+
}
/**
@@ -2388,11 +2209,9 @@ public final class NfcAdapter {
synchronized (mLock) {
mTagRemovedListener = iListener;
}
- try {
- return sService.ignore(tag.getServiceHandle(), debounceMs, iListener);
- } catch (RemoteException e) {
- return false;
- }
+ final ITagRemovedCallback.Stub passedListener = iListener;
+ return callServiceReturn(() ->
+ sService.ignore(tag.getServiceHandle(), debounceMs, passedListener), false);
}
/**
@@ -2509,22 +2328,9 @@ public final class NfcAdapter {
throw new UnsupportedOperationException("You need a context on NfcAdapter to use the "
+ " NFC extras APIs");
}
- try {
- return sService.getNfcAdapterExtrasInterface(mContext.getPackageName());
- } catch (RemoteException e) {
- attemptDeadServiceRecovery(e);
- // Try one more time
- if (sService == null) {
- Log.e(TAG, "Failed to recover NFC Service.");
- return null;
- }
- try {
- return sService.getNfcAdapterExtrasInterface(mContext.getPackageName());
- } catch (RemoteException ee) {
- Log.e(TAG, "Failed to recover NFC Service.");
- }
- return null;
- }
+ return callServiceReturn(() ->
+ sService.getNfcAdapterExtrasInterface(mContext.getPackageName()), null);
+
}
void enforceResumed(Activity activity) {
@@ -2569,22 +2375,8 @@ public final class NfcAdapter {
if (!sHasNfcFeature && !sHasCeFeature) {
throw new UnsupportedOperationException();
}
- try {
- return sService.setControllerAlwaysOn(value);
- } catch (RemoteException e) {
- attemptDeadServiceRecovery(e);
- // Try one more time
- if (sService == null) {
- Log.e(TAG, "Failed to recover NFC Service.");
- return false;
- }
- try {
- return sService.setControllerAlwaysOn(value);
- } catch (RemoteException ee) {
- Log.e(TAG, "Failed to recover NFC Service.");
- }
- return false;
- }
+ return callServiceReturn(() -> sService.setControllerAlwaysOn(value), false);
+
}
/**
@@ -2600,22 +2392,8 @@ public final class NfcAdapter {
@SystemApi
@RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON)
public boolean isControllerAlwaysOn() {
- try {
- return sService.isControllerAlwaysOn();
- } catch (RemoteException e) {
- attemptDeadServiceRecovery(e);
- // Try one more time
- if (sService == null) {
- Log.e(TAG, "Failed to recover NFC Service.");
- return false;
- }
- try {
- return sService.isControllerAlwaysOn();
- } catch (RemoteException ee) {
- Log.e(TAG, "Failed to recover NFC Service.");
- }
- return false;
- }
+ return callServiceReturn(() -> sService.isControllerAlwaysOn(), false);
+
}
/**
@@ -2634,22 +2412,8 @@ public final class NfcAdapter {
if (!sHasNfcFeature && !sHasCeFeature) {
throw new UnsupportedOperationException();
}
- try {
- return sService.isControllerAlwaysOnSupported();
- } catch (RemoteException e) {
- attemptDeadServiceRecovery(e);
- // Try one more time
- if (sService == null) {
- Log.e(TAG, "Failed to recover NFC Service.");
- return false;
- }
- try {
- return sService.isControllerAlwaysOnSupported();
- } catch (RemoteException ee) {
- Log.e(TAG, "Failed to recover NFC Service.");
- }
- return false;
- }
+ return callServiceReturn(() -> sService.isControllerAlwaysOnSupported(), false);
+
}
/**
@@ -2719,21 +2483,9 @@ public final class NfcAdapter {
Log.e(TAG, "TagIntentAppPreference is not supported");
throw new UnsupportedOperationException();
}
- try {
- return sService.setTagIntentAppPreferenceForUser(userId, pkg, allow);
- } catch (RemoteException e) {
- attemptDeadServiceRecovery(e);
- // Try one more time
- if (sService == null) {
- Log.e(TAG, "Failed to recover NFC Service.");
- }
- try {
- return sService.setTagIntentAppPreferenceForUser(userId, pkg, allow);
- } catch (RemoteException ee) {
- Log.e(TAG, "Failed to recover NFC Service.");
- }
- return TAG_INTENT_APP_PREF_RESULT_UNAVAILABLE;
- }
+ return callServiceReturn(() ->
+ sService.setTagIntentAppPreferenceForUser(userId, pkg, allow),
+ TAG_INTENT_APP_PREF_RESULT_UNAVAILABLE);
}
@@ -2808,22 +2560,8 @@ public final class NfcAdapter {
if (!sHasNfcFeature) {
throw new UnsupportedOperationException();
}
- try {
- return sService.isTagIntentAppPreferenceSupported();
- } catch (RemoteException e) {
- attemptDeadServiceRecovery(e);
- // Try one more time
- if (sService == null) {
- Log.e(TAG, "Failed to recover NFC Service.");
- return false;
- }
- try {
- return sService.isTagIntentAppPreferenceSupported();
- } catch (RemoteException ee) {
- Log.e(TAG, "Failed to recover NFC Service.");
- }
- return false;
- }
+ return callServiceReturn(() -> sService.isTagIntentAppPreferenceSupported(), false);
+
}
/**
@@ -2836,11 +2574,30 @@ public final class NfcAdapter {
@TestApi
@FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP)
public void notifyPollingLoop(@NonNull PollingFrame pollingFrame) {
+ callService(() -> sService.notifyPollingLoop(pollingFrame));
+ }
+
+
+ /**
+ * Notifies the system of new HCE data for tests.
+ *
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP)
+ public void notifyTestHceData(int technology, byte[] data) {
+ callService(() -> sService.notifyTestHceData(technology, data));
+ }
+
+ interface ServiceCall {
+ void call() throws RemoteException;
+ }
+
+ void callService(ServiceCall call) {
try {
if (sService == null) {
attemptDeadServiceRecovery(null);
}
- sService.notifyPollingLoop(pollingFrame);
+ call.call();
} catch (RemoteException e) {
attemptDeadServiceRecovery(e);
// Try one more time
@@ -2849,39 +2606,46 @@ public final class NfcAdapter {
return;
}
try {
- sService.notifyPollingLoop(pollingFrame);
+ call.call();
} catch (RemoteException ee) {
Log.e(TAG, "Failed to recover NFC Service.");
}
}
}
-
- /**
- * Notifies the system of a an HCE session being deactivated.
- * *
- * @hide
- */
- @TestApi
- @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP)
- public void notifyHceDeactivated() {
+ interface ServiceCallReturn<T> {
+ T call() throws RemoteException;
+ }
+ <T> T callServiceReturn(ServiceCallReturn<T> call, T defaultReturn) {
try {
if (sService == null) {
attemptDeadServiceRecovery(null);
}
- sService.notifyHceDeactivated();
+ return call.call();
} catch (RemoteException e) {
attemptDeadServiceRecovery(e);
// Try one more time
if (sService == null) {
Log.e(TAG, "Failed to recover NFC Service.");
- return;
+ return defaultReturn;
}
try {
- sService.notifyHceDeactivated();
+ return call.call();
} catch (RemoteException ee) {
Log.e(TAG, "Failed to recover NFC Service.");
}
}
+ return defaultReturn;
+ }
+
+ /**
+ * Notifies the system of a an HCE session being deactivated.
+ * *
+ * @hide
+ */
+ @TestApi
+ @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP)
+ public void notifyHceDeactivated() {
+ callService(() -> sService.notifyHceDeactivated());
}
/**
@@ -2897,22 +2661,7 @@ public final class NfcAdapter {
if (!sHasNfcWlcFeature) {
throw new UnsupportedOperationException();
}
- try {
- return sService.setWlcEnabled(enable);
- } catch (RemoteException e) {
- attemptDeadServiceRecovery(e);
- // Try one more time
- if (sService == null) {
- Log.e(TAG, "Failed to recover NFC Service.");
- return false;
- }
- try {
- return sService.setWlcEnabled(enable);
- } catch (RemoteException ee) {
- Log.e(TAG, "Failed to recover NFC Service.");
- }
- return false;
- }
+ return callServiceReturn(() -> sService.setWlcEnabled(enable), false);
}
/**
@@ -2927,22 +2676,8 @@ public final class NfcAdapter {
if (!sHasNfcWlcFeature) {
throw new UnsupportedOperationException();
}
- try {
- return sService.isWlcEnabled();
- } catch (RemoteException e) {
- attemptDeadServiceRecovery(e);
- // Try one more time
- if (sService == null) {
- Log.e(TAG, "Failed to recover NFC Service.");
- return false;
- }
- try {
- return sService.isWlcEnabled();
- } catch (RemoteException ee) {
- Log.e(TAG, "Failed to recover NFC Service.");
- }
- return false;
- }
+ return callServiceReturn(() -> sService.isWlcEnabled(), false);
+
}
/**
@@ -3021,22 +2756,8 @@ public final class NfcAdapter {
if (!sHasNfcWlcFeature) {
throw new UnsupportedOperationException();
}
- try {
- return sService.getWlcListenerDeviceInfo();
- } catch (RemoteException e) {
- attemptDeadServiceRecovery(e);
- // Try one more time
- if (sService == null) {
- Log.e(TAG, "Failed to recover NFC Service.");
- return null;
- }
- try {
- return sService.getWlcListenerDeviceInfo();
- } catch (RemoteException ee) {
- Log.e(TAG, "Failed to recover NFC Service.");
- }
- return null;
- }
+ return callServiceReturn(() -> sService.getWlcListenerDeviceInfo(), null);
+
}
/**
diff --git a/packages/CarrierDefaultApp/res/values-fr-rCA/strings.xml b/packages/CarrierDefaultApp/res/values-fr-rCA/strings.xml
index 54dae628ba88..91da7dcdf977 100644
--- a/packages/CarrierDefaultApp/res/values-fr-rCA/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-fr-rCA/strings.xml
@@ -16,7 +16,7 @@
<string name="ssl_error_continue" msgid="1138548463994095584">"Continuer quand même dans un navigateur"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Optimiseur de performances"</string>
<string name="performance_boost_notification_title" msgid="3126203390685781861">"Options 5G de votre fournisseur de services"</string>
- <string name="performance_boost_notification_detail" msgid="216569851036236346">"Consultez le site Web de %s pour voir les options concernant votre expérience de l\'application"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"Consultez le site Web de %s pour voir les options concernant votre expérience de l\'appli"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Plus tard"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Gérer"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Achetez un optimiseur de performances."</string>
diff --git a/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml b/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml
index 97abef773a52..5b5896109846 100644
--- a/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml
@@ -17,20 +17,20 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Gestionnaire d\'appareil compagnon"</string>
- <string name="confirmation_title" msgid="2244241995958340998">"Autoriser l\'application &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; à accéder à &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"Autoriser l\'appli &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; à accéder à &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"montre"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Choisir un appareil qui sera géré par &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
<string name="chooser_title" msgid="2235819929238267637">"Choisir un appareil (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>) pour le configurer"</string>
- <string name="summary_watch" msgid="7962014927042971830">"Cette application sera autorisée à synchroniser des informations, comme le nom de l\'appelant, et à accéder à ces autorisations sur votre <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="summary_watch" msgid="7962014927042971830">"Cette appli sera autorisée à synchroniser des informations, comme le nom de l\'appelant, et à accéder à ces autorisations sur votre <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Autoriser &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; à gérer &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"appareil"</string>
- <string name="summary_glasses" msgid="2872254734959842579">"Cette application pourra accéder à ces autorisations sur votre <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="summary_glasses" msgid="2872254734959842579">"Cette appli pourra accéder à ces autorisations sur votre <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Autorisez &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; à accéder à ces informations à partir de votre téléphone"</string>
- <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"Autoriser &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; à diffuser les applications de votre téléphone?"</string>
- <string name="summary_app_streaming" msgid="295548145144086753">"%1$s aura accès à tout ce qui est visible ou lu sur le téléphone, y compris l\'audio, les photos, les mots de passe et les messages.&lt;br/&gt;&lt;br/&gt;%1$s pourra diffuser des applications jusqu\'à ce que vous retiriez l\'accès à cette autorisation."</string>
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"Autoriser &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; à diffuser les applis de votre téléphone?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"%1$s aura accès à tout ce qui est visible ou lu sur le téléphone, y compris l\'audio, les photos, les mots de passe et les messages.&lt;br/&gt;&lt;br/&gt;%1$s pourra diffuser des applis jusqu\'à ce que vous retiriez l\'accès à cette autorisation."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Services multiappareils"</string>
- <string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> demande l\'autorisation au nom de votre <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> pour diffuser des applications entre vos appareils"</string>
- <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> demande l\'autorisation, au nom de votre <xliff:g id="DISPLAY_NAME">%2$s</xliff:g>, d\'afficher et de diffuser des applications entre vos appareils"</string>
+ <string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> demande l\'autorisation au nom de votre <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> pour diffuser des applis entre vos appareils"</string>
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> demande l\'autorisation, au nom de votre <xliff:g id="DISPLAY_NAME">%2$s</xliff:g>, d\'afficher et de diffuser des applis entre vos appareils"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Autorisez &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; à accéder à ces informations à partir de votre téléphone"</string>
@@ -38,18 +38,18 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Services Google Play"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g> demande l\'autorisation au nom de votre <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> pour accéder aux photos, aux fichiers multimédias et aux notifications de votre téléphone"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Autoriser &lt;strong&gt;<xliff:g id="DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; à effectuer cette action?"</string>
- <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"Autoriser &lt;strong&gt;<xliff:g id="DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; à diffuser les applications et les fonctionnalités du système de votre téléphone?"</string>
- <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s aura accès à tout ce qui est visible ou lu sur le téléphone, y compris l\'audio, les photos, les renseignements de paiement, les mots de passe et les messages.&lt;br/&gt;&lt;br/&gt;%1$s pourra diffuser des applications jusqu\'à ce que vous retiriez l\'accès à cette autorisation."</string>
- <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> demande l\'autorisation, au nom de votre <xliff:g id="DEVICE_NAME">%2$s</xliff:g>, de diffuser des applications et d\'autres fonctionnalités du système sur des appareils à proximité"</string>
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"Autoriser &lt;strong&gt;<xliff:g id="DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; à diffuser les applis et les fonctionnalités du système de votre téléphone?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s aura accès à tout ce qui est visible ou lu sur le téléphone, y compris l\'audio, les photos, les renseignements de paiement, les mots de passe et les messages.&lt;br/&gt;&lt;br/&gt;%1$s pourra diffuser des applis jusqu\'à ce que vous retiriez l\'accès à cette autorisation."</string>
+ <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> demande l\'autorisation, au nom de votre <xliff:g id="DEVICE_NAME">%2$s</xliff:g>, de diffuser des applis et d\'autres fonctionnalités du système sur des appareils à proximité"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"appareil"</string>
- <string name="summary_generic" msgid="1761976003668044801">"Cette application pourra synchroniser des informations, comme le nom de l\'appelant, entre votre téléphone et l\'appareil sélectionné"</string>
+ <string name="summary_generic" msgid="1761976003668044801">"Cette appli pourra synchroniser des informations, comme le nom de l\'appelant, entre votre téléphone et l\'appareil sélectionné"</string>
<string name="consent_yes" msgid="8344487259618762872">"Autoriser"</string>
<string name="consent_no" msgid="2640796915611404382">"Ne pas autoriser"</string>
<string name="consent_cancel" msgid="5655005528379285841">"Annuler"</string>
<string name="consent_back" msgid="2560683030046918882">"Retour"</string>
<string name="permission_expand" msgid="893185038020887411">"Développer <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
<string name="permission_collapse" msgid="3320833884220844084">"Réduire <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
- <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Accorder aux applications sur &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; les autorisations déjà accordées sur &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Accorder aux applis sur &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; les autorisations déjà accordées sur &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
<string name="permission_sync_summary" msgid="765497944331294275">"Cela peut inclure l\'accès &lt;strong&gt;au microphone&lt;/strong&gt;, &lt;strong&gt;à l\'appareil photo&lt;/strong&gt;, et &lt;strong&gt;à la position&lt;/strong&gt;, ainsi que d\'autres autorisations sensibles sur &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;. &lt;br/&gt;&lt;br/&gt;Vous pouvez modifier ces autorisations à tout moment dans vos paramètres sur &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;."</string>
<string name="vendor_header_button_description" msgid="7994879208461111473">"Plus de renseignements"</string>
<string name="permission_phone" msgid="2661081078692784919">"Téléphone"</string>
@@ -62,7 +62,7 @@
<string name="permission_media_routing_control" msgid="5498639511586715253">"Modifier la sortie multimédia"</string>
<string name="permission_storage" msgid="6831099350839392343">"Photos et fichiers multimédias"</string>
<string name="permission_notifications" msgid="4099418516590632909">"Notifications"</string>
- <string name="permission_app_streaming" msgid="6009695219091526422">"Applications"</string>
+ <string name="permission_app_streaming" msgid="6009695219091526422">"Applis"</string>
<string name="permission_nearby_device_streaming" msgid="1023325519477349499">"Diffusion en continu"</string>
<string name="permission_phone_summary" msgid="8246321093970051702">"Passez et gérez des appels téléphoniques"</string>
<string name="permission_call_logs_summary" msgid="7545243592757693321">"Lisez et écrivez le journal d\'appels téléphoniques"</string>
@@ -72,11 +72,11 @@
<string name="permission_microphone_summary" msgid="4862628553869973259">"Enregistrez des fichiers audio"</string>
<string name="permission_nearby_devices_summary" msgid="1306752848196464817">"Trouvez et déterminez la position relative des appareils à proximité, et connectez-vous à ceux-ci"</string>
<string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"Lisez toutes les notifications, y compris les renseignements tels que les contacts, les messages et les photos"</string>
- <string name="permission_notifications_summary" msgid="2272810466047367030">"• Lisez toutes les notifications, y compris les renseignements tels que les contacts, les messages et les photos&lt;br/&gt;• Envoyez des notifications&lt;br/&gt;&lt;br/&gt;Vous pouvez gérer la capacité de cette application à lire et à envoyer des notifications à tout moment dans Paramètres > Notifications."</string>
- <string name="permission_app_streaming_summary" msgid="606923325679670624">"Diffusez les applications de votre téléphone"</string>
+ <string name="permission_notifications_summary" msgid="2272810466047367030">"• Lisez toutes les notifications, y compris les renseignements tels que les contacts, les messages et les photos&lt;br/&gt;• Envoyez des notifications&lt;br/&gt;&lt;br/&gt;Vous pouvez gérer la capacité de cette appli à lire et à envoyer des notifications à tout moment dans Paramètres > Notifications."</string>
+ <string name="permission_app_streaming_summary" msgid="606923325679670624">"Diffusez les applis de votre téléphone"</string>
<string name="permission_storage_summary" msgid="3918240895519506417"></string>
- <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"Diffusez des applications et d\'autres fonctionnalités du système à partir de votre téléphone"</string>
- <string name="permission_media_routing_control_summary" msgid="2714631092321412250">"Accédez à une liste d\'appareils accessibles et contrôlez ceux qui diffusent du contenu audio ou vidéo à partir d\'autres applications"</string>
+ <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"Diffusez des applis et d\'autres fonctionnalités du système à partir de votre téléphone"</string>
+ <string name="permission_media_routing_control_summary" msgid="2714631092321412250">"Accédez à une liste d\'appareils accessibles et contrôlez ceux qui diffusent du contenu audio ou vidéo à partir d\'autres applis"</string>
<string name="device_type" product="default" msgid="8268703872070046263">"téléphone"</string>
<string name="device_type" product="tablet" msgid="5038791954983067774">"tablette"</string>
</resources>
diff --git a/packages/CrashRecovery/aconfig/flags.aconfig b/packages/CrashRecovery/aconfig/flags.aconfig
index 225f8c685fe1..52e0cbbda03a 100644
--- a/packages/CrashRecovery/aconfig/flags.aconfig
+++ b/packages/CrashRecovery/aconfig/flags.aconfig
@@ -31,3 +31,11 @@ flag {
description: "Deletes flag and settings resets"
bug: "333847376"
}
+
+flag {
+ name: "refactor_crashrecovery"
+ namespace: "modularization"
+ description: "Refactor required CrashRecovery code"
+ bug: "289203818"
+ is_fixed_read_only: true
+}
diff --git a/packages/CredentialManager/res/values-el/strings.xml b/packages/CredentialManager/res/values-el/strings.xml
index 2f3aa0bce6f2..8436e21f01d3 100644
--- a/packages/CredentialManager/res/values-el/strings.xml
+++ b/packages/CredentialManager/res/values-el/strings.xml
@@ -53,7 +53,7 @@
<string name="save_password_on_other_device_title" msgid="5829084591948321207">"Θέλετε να αποθηκεύσετε τον κωδικό πρόσβασης σε κάποια άλλη συσκευή;"</string>
<string name="save_sign_in_on_other_device_title" msgid="2827990118560134692">"Θέλετε να αποθηκεύσετε τα στοιχεία σύνδεσης σε κάποια άλλη συσκευή;"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Να χρησιμοποιηθεί το <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> για όλες τις συνδέσεις σας;"</string>
- <string name="use_provider_for_all_description" msgid="1998772715863958997">"Αυτός ο διαχειριστής κωδικών πρόσβασης για τον χρήστη <xliff:g id="USERNAME">%1$s</xliff:g> θα αποθηκεύει τους κωδικούς και τα κλειδιά πρόσβασης, για πιο εύκολη σύνδεση"</string>
+ <string name="use_provider_for_all_description" msgid="1998772715863958997">"Αυτή η διαχείριση κωδικών πρόσβασης για τον χρήστη <xliff:g id="USERNAME">%1$s</xliff:g> θα αποθηκεύει τους κωδικούς και τα κλειδιά πρόσβασης, για πιο εύκολη σύνδεση"</string>
<string name="set_as_default" msgid="4415328591568654603">"Ορισμός ως προεπιλογής"</string>
<string name="settings" msgid="6536394145760913145">"Ρυθμίσεις"</string>
<string name="use_once" msgid="9027366575315399714">"Χρήση μία φορά"</string>
diff --git a/packages/CredentialManager/res/values-fr-rCA/strings.xml b/packages/CredentialManager/res/values-fr-rCA/strings.xml
index d9715eefa955..d68de9fcd27c 100644
--- a/packages/CredentialManager/res/values-fr-rCA/strings.xml
+++ b/packages/CredentialManager/res/values-fr-rCA/strings.xml
@@ -32,9 +32,9 @@
<string name="passwordless_technology_title" msgid="2497513482056606668">"Technologie sans mot de passe"</string>
<string name="passwordless_technology_detail" msgid="6853928846532955882">"Les clés d\'accès vous permettent de vous connecter sans utiliser de mots de passe. Il vous suffit d\'utiliser votre empreinte digitale, la reconnaissance faciale, un NIP ou un schéma de balayage pour vérifier votre identité et créer un mot de passe."</string>
<string name="public_key_cryptography_title" msgid="6751970819265298039">"Cryptographie à clé publique"</string>
- <string name="public_key_cryptography_detail" msgid="6937631710280562213">"Selon les normes de l\'Alliance FIDO (y compris Google, Apple, Microsoft et plus) et du W3C, les clés d\'accès utilisent des biclés cryptographiques. Contrairement au nom d\'utilisateur et à la chaîne de caractères que nous utilisons pour les mots de passe, une biclé privée-publique est créée pour une application ou un site Web. La clé privée est stockée en toute sécurité sur votre appareil ou votre gestionnaire de mots de passe et confirme votre identité. La clé publique est partagée avec le serveur de l\'application ou du site Web. Avec les clés correspondantes, vous pouvez vous inscrire et vous connecter instantanément."</string>
+ <string name="public_key_cryptography_detail" msgid="6937631710280562213">"Selon les normes de l\'Alliance FIDO (y compris Google, Apple, Microsoft et plus) et du W3C, les clés d\'accès utilisent des biclés cryptographiques. Contrairement au nom d\'utilisateur et à la chaîne de caractères que nous utilisons pour les mots de passe, une biclé privée-publique est créée pour une appli ou un site Web. La clé privée est stockée en toute sécurité sur votre appareil ou votre gestionnaire de mots de passe et confirme votre identité. La clé publique est partagée avec le serveur de l\'appli ou du site Web. Avec les clés correspondantes, vous pouvez vous inscrire et vous connecter instantanément."</string>
<string name="improved_account_security_title" msgid="1069841917893513424">"Sécurité accrue du compte"</string>
- <string name="improved_account_security_detail" msgid="9123750251551844860">"Chaque clé est exclusivement liée à l\'application ou au site Web pour lequel elle a été créée, de sorte que vous ne pourrez jamais vous connecter par erreur à une application ou à un site Web frauduleux. En outre, comme les serveurs ne conservent que les clés publiques, le piratage informatique est beaucoup plus difficile."</string>
+ <string name="improved_account_security_detail" msgid="9123750251551844860">"Chaque clé est exclusivement liée à l\'appli ou au site Web pour lequel elle a été créée, de sorte que vous ne pourrez jamais vous connecter par erreur à une appli ou à un site Web frauduleux. En outre, comme les serveurs ne conservent que les clés publiques, le piratage informatique est beaucoup plus difficile."</string>
<string name="seamless_transition_title" msgid="5335622196351371961">"Transition fluide"</string>
<string name="seamless_transition_detail" msgid="4475509237171739843">"À mesure que nous nous dirigeons vers un avenir sans mot de passe, ils resteront toujours utilisés parallèlement aux clés d\'accès."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"Choisir où enregistrer vos <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-pa/strings.xml b/packages/CredentialManager/res/values-pa/strings.xml
index 517fd82e614a..309299cbf88c 100644
--- a/packages/CredentialManager/res/values-pa/strings.xml
+++ b/packages/CredentialManager/res/values-pa/strings.xml
@@ -32,7 +32,7 @@
<string name="passwordless_technology_title" msgid="2497513482056606668">"ਪਾਸਵਰਡ ਰਹਿਤ ਤਕਨਾਲੋਜੀ"</string>
<string name="passwordless_technology_detail" msgid="6853928846532955882">"ਪਾਸਕੀਆਂ ਤੁਹਾਨੂੰ ਪਾਸਵਰਡਾਂ \'ਤੇ ਭਰੋਸਾ ਕੀਤੇ ਬਿਨਾਂ ਸਾਈਨ-ਇਨ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦੀਆਂ ਹਨ। ਤੁਹਾਨੂੰ ਆਪਣੀ ਪਛਾਣ ਦੀ ਪੁਸ਼ਟੀ ਕਰਨ ਅਤੇ ਪਾਸਕੀ ਬਣਾਉਣ ਲਈ ਸਿਰਫ਼ ਆਪਣੇ ਫਿੰਗਰਪ੍ਰਿੰਟ, ਚਿਹਰਾ ਪਛਾਣ, ਪਿੰਨ ਜਾਂ ਸਵਾਈਪ ਪੈਟਰਨ ਦੀ ਵਰਤੋਂ ਕਰਨ ਦੀ ਲੋੜ ਹੈ।"</string>
<string name="public_key_cryptography_title" msgid="6751970819265298039">"ਜਨਤਕ ਕੁੰਜੀ ਕ੍ਰਿਪਟੋਗ੍ਰਾਫ਼ੀ"</string>
- <string name="public_key_cryptography_detail" msgid="6937631710280562213">"FIDO ਗਠਜੋੜ (ਜਿਸ ਵਿੱਚ Google, Apple, Microsoft ਅਤੇ ਹੋਰ ਸ਼ਾਮਲ ਹਨ) ਅਤੇ W3C ਮਿਆਰਾਂ ਦੇ ਆਧਾਰ \'ਤੇ ਪਾਸਕੀਆਂ ਕ੍ਰਿਪਟੋਗ੍ਰਾਫ਼ਿਕ ਕੁੰਜੀਆਂ ਦੇ ਜੋੜੇ ਵਰਤਦੀਆਂ ਹਨ। ਪਾਸਵਰਡ ਲਈ ਵਰਤੀ ਜਾਂਦੀ ਅੱਖਰ-ਚਿੰਨ੍ਹਾਂ ਦੀ ਸਤਰ ਅਤੇ ਵਰਤੋਂਕਾਰ ਨਾਮ ਤੋਂ ਅਲੱਗ, ਐਪ ਜਾਂ ਵੈੱਬਸਾਈਟ ਲਈ ਨਿੱਜੀ-ਜਨਤਕ ਕੁੰਜੀ ਜੋੜਾ ਬਣਾਇਆ ਜਾਂਦਾ ਹੈ। ਨਿੱਜੀ ਕੁੰਜੀ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਜਾਂ ਪਾਸਵਰਡ ਪ੍ਰਬੰਧਕ \'ਤੇ ਸੁਰੱਖਿਅਤ ਢੰਗ ਨਾਲ ਸਟੋਰ ਕੀਤੀ ਜਾਂਦੀ ਹੈ ਅਤੇ ਤੁਹਾਡੀ ਪਛਾਣ ਦੀ ਪੁਸ਼ਟੀ ਕਰਦੀ ਹੈ। ਜਨਤਕ ਕੁੰਜੀ ਐਪ ਜਾਂ ਵੈੱਬਸਾਈਟ ਸਰਵਰ ਨਾਲ ਸਾਂਝੀ ਕੀਤੀ ਜਾਂਦੀ ਹੈ। ਸੰਬੰਧਿਤ ਕੁੰਜੀਆਂ ਨਾਲ, ਤੁਸੀਂ ਤੁਰੰਤ ਰਜਿਸਟਰ ਅਤੇ ਸਾਈਨ-ਇਨ ਕਰ ਸਕਦੇ ਹੋ।"</string>
+ <string name="public_key_cryptography_detail" msgid="6937631710280562213">"FIDO ਗਠਜੋੜ (Google, Apple, Microsoft ਅਤੇ ਹੋਰ) ਅਤੇ W3C ਮਿਆਰਾਂ ਦੇ ਆਧਾਰ \'ਤੇ ਪਾਸਕੀਆਂ ਕ੍ਰਿਪਟੋਗ੍ਰਾਫ਼ਿਕ ਕੁੰਜੀਆਂ ਦੇ ਜੋੜੇ ਵਰਤਦੀਆਂ ਹਨ। ਪਾਸਵਰਡ ਲਈ ਵਰਤੀ ਜਾਂਦੀ ਅੱਖਰ-ਚਿੰਨ੍ਹਾਂ ਦੀ ਸਤਰ ਅਤੇ ਵਰਤੋਂਕਾਰ ਨਾਮ ਤੋਂ ਅਲੱਗ, ਐਪ ਜਾਂ ਵੈੱਬਸਾਈਟ ਲਈ ਪ੍ਰਾਈਵੇਟ-ਜਨਤਕ ਕੁੰਜੀ ਜੋੜਾ ਬਣਾਇਆ ਜਾਂਦਾ ਹੈ। ਪ੍ਰਾਈਵੇਟ ਕੁੰਜੀ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਜਾਂ ਪਾਸਵਰਡ ਪ੍ਰਬੰਧਕ \'ਤੇ ਸੁਰੱਖਿਅਤ ਢੰਗ ਨਾਲ ਸਟੋਰ ਕੀਤੀ ਜਾਂਦੀ ਹੈ ਅਤੇ ਤੁਹਾਡੀ ਪਛਾਣ ਦੀ ਪੁਸ਼ਟੀ ਕਰਦੀ ਹੈ। ਜਨਤਕ ਕੁੰਜੀ ਐਪ ਜਾਂ ਵੈੱਬਸਾਈਟ ਸਰਵਰ ਨਾਲ ਸਾਂਝੀ ਕੀਤੀ ਜਾਂਦੀ ਹੈ। ਸੰਬੰਧਿਤ ਕੁੰਜੀਆਂ ਨਾਲ, ਤੁਸੀਂ ਤੁਰੰਤ ਰਜਿਸਟਰ ਅਤੇ ਸਾਈਨ-ਇਨ ਕਰ ਸਕਦੇ ਹੋ।"</string>
<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>
diff --git a/packages/CredentialManager/wear/res/values-am/strings.xml b/packages/CredentialManager/wear/res/values-am/strings.xml
new file mode 100644
index 000000000000..4aa4af184752
--- /dev/null
+++ b/packages/CredentialManager/wear/res/values-am/strings.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="7384524142163511792">"የመግቢያ ማስረጃ አስተዳዳሪ"</string>
+ <string name="use_passkey_title" msgid="716598039340757817">"የይለፍ ቁልፍ ይጠቀማሉ?"</string>
+ <string name="use_password_title" msgid="4655101984031246476">"የይለፍ ቃል ይጠቀማሉ?"</string>
+ <string name="dialog_dismiss_button" msgid="989567669882005067">"አሰናብት"</string>
+ <string name="dialog_continue_button" msgid="8630290044077052145">"ቀጥል"</string>
+ <string name="dialog_sign_in_options_button" msgid="448002958902615054">"የመግቢያ አማራጮች"</string>
+ <string name="sign_in_options_title" msgid="6720572645638986680">"የመግቢያ አማራጮች"</string>
+ <string name="provider_list_title" msgid="6803918216129492212">"መግቢያዎችን ያስተዳድሩ"</string>
+ <string name="choose_sign_in_title" msgid="3616025924746872202">"መግቢያ ይምረጡ"</string>
+ <string name="choose_passkey_title" msgid="8459270617632817465">"የይለፍ ቁልፍ ይምረጡ"</string>
+ <string name="choose_password_title" msgid="7610721820858017214">"የይለፍ ቃል ይምረጡ"</string>
+ <string name="sign_in_on_phone_button" msgid="7618621977586522403">"በስልክ ላይ ግባ"</string>
+ <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="1733094937495140605">"ምንም የመግቢያ መረጃ የለም"</string>
+ <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="4320941096211904568">"ለመክፈት መታ ያድርጉ"</string>
+</resources>
diff --git a/packages/CredentialManager/wear/res/values-as/strings.xml b/packages/CredentialManager/wear/res/values-as/strings.xml
new file mode 100644
index 000000000000..7b6055dd5372
--- /dev/null
+++ b/packages/CredentialManager/wear/res/values-as/strings.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="7384524142163511792">"ক্ৰিডেনশ্বিয়েল পৰিচালক"</string>
+ <string name="use_passkey_title" msgid="716598039340757817">"পাছকী ব্যৱহাৰ কৰিবনে?"</string>
+ <string name="use_password_title" msgid="4655101984031246476">"পাছৱৰ্ড ব্যৱহাৰ কৰিবনে?"</string>
+ <string name="dialog_dismiss_button" msgid="989567669882005067">"অগ্ৰাহ্য কৰক"</string>
+ <string name="dialog_continue_button" msgid="8630290044077052145">"অব্যাহত ৰাখক"</string>
+ <string name="dialog_sign_in_options_button" msgid="448002958902615054">"ছাইন ইন কৰাৰ বিকল্প"</string>
+ <string name="sign_in_options_title" msgid="6720572645638986680">"ছাইন ইন কৰাৰ বিকল্প"</string>
+ <string name="provider_list_title" msgid="6803918216129492212">"ছাইন ইন পৰিচালনা কৰক"</string>
+ <string name="choose_sign_in_title" msgid="3616025924746872202">"এটা ছাইন ইনৰ উপায় বাছনি কৰক"</string>
+ <string name="choose_passkey_title" msgid="8459270617632817465">"পাছকী বাছনি কৰক"</string>
+ <string name="choose_password_title" msgid="7610721820858017214">"পাছৱৰ্ড বাছনি কৰক"</string>
+ <string name="sign_in_on_phone_button" msgid="7618621977586522403">"ফ’নত ছাইন ইন কৰক"</string>
+ <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="1733094937495140605">"ছাইন ইনৰ তথ্য নাই"</string>
+ <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="4320941096211904568">"আনলক কৰিবলৈ টিপক"</string>
+</resources>
diff --git a/packages/CredentialManager/wear/res/values-cs/strings.xml b/packages/CredentialManager/wear/res/values-cs/strings.xml
new file mode 100644
index 000000000000..ba60a8c6440a
--- /dev/null
+++ b/packages/CredentialManager/wear/res/values-cs/strings.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="7384524142163511792">"Správce oprávnění"</string>
+ <string name="use_passkey_title" msgid="716598039340757817">"Použít přístupový klíč?"</string>
+ <string name="use_password_title" msgid="4655101984031246476">"Použít heslo?"</string>
+ <string name="dialog_dismiss_button" msgid="989567669882005067">"Zavřít"</string>
+ <string name="dialog_continue_button" msgid="8630290044077052145">"Pokračovat"</string>
+ <string name="dialog_sign_in_options_button" msgid="448002958902615054">"Možnosti přihlášení"</string>
+ <string name="sign_in_options_title" msgid="6720572645638986680">"Možnosti přihlášení"</string>
+ <string name="provider_list_title" msgid="6803918216129492212">"Spravovat přihlášení"</string>
+ <string name="choose_sign_in_title" msgid="3616025924746872202">"Vyberte přihlášení"</string>
+ <string name="choose_passkey_title" msgid="8459270617632817465">"Vyberte přístupový klíč"</string>
+ <string name="choose_password_title" msgid="7610721820858017214">"Vyberte heslo"</string>
+ <string name="sign_in_on_phone_button" msgid="7618621977586522403">"Přihlásit se z telefonu"</string>
+ <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="1733094937495140605">"Žádné informace o přihlášení"</string>
+ <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="4320941096211904568">"Klepnutím odemknete"</string>
+</resources>
diff --git a/packages/CredentialManager/wear/res/values-el/strings.xml b/packages/CredentialManager/wear/res/values-el/strings.xml
new file mode 100644
index 000000000000..1c9d49bb8749
--- /dev/null
+++ b/packages/CredentialManager/wear/res/values-el/strings.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="7384524142163511792">"Διαχειριστής διαπιστευτηρίων"</string>
+ <string name="use_passkey_title" msgid="716598039340757817">"Χρήση κλειδιού πρόσβασης;"</string>
+ <string name="use_password_title" msgid="4655101984031246476">"Χρήση κωδικού πρόσβασης;"</string>
+ <string name="dialog_dismiss_button" msgid="989567669882005067">"Παράβλεψη"</string>
+ <string name="dialog_continue_button" msgid="8630290044077052145">"Συνέχεια"</string>
+ <string name="dialog_sign_in_options_button" msgid="448002958902615054">"Επιλογές σύνδεσης"</string>
+ <string name="sign_in_options_title" msgid="6720572645638986680">"Επιλογές σύνδεσης"</string>
+ <string name="provider_list_title" msgid="6803918216129492212">"Διαχείριση στοιχείων σύνδεσης"</string>
+ <string name="choose_sign_in_title" msgid="3616025924746872202">"Επιλογή σύνδεσης"</string>
+ <string name="choose_passkey_title" msgid="8459270617632817465">"Επιλογή κλειδιού πρόσβασης"</string>
+ <string name="choose_password_title" msgid="7610721820858017214">"Επιλογή κωδικού πρόσβασης"</string>
+ <string name="sign_in_on_phone_button" msgid="7618621977586522403">"Σύνδεση στο τηλέφωνο"</string>
+ <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="1733094937495140605">"Δεν υπάρχουν πληροφορίες σύνδεσης"</string>
+ <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="4320941096211904568">"Πατήστε για ξεκλείδωμα"</string>
+</resources>
diff --git a/packages/CredentialManager/wear/res/values-en-rAU/strings.xml b/packages/CredentialManager/wear/res/values-en-rAU/strings.xml
new file mode 100644
index 000000000000..75a0a0067e31
--- /dev/null
+++ b/packages/CredentialManager/wear/res/values-en-rAU/strings.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="7384524142163511792">"Credential Manager"</string>
+ <string name="use_passkey_title" msgid="716598039340757817">"Use passkey?"</string>
+ <string name="use_password_title" msgid="4655101984031246476">"Use password?"</string>
+ <string name="dialog_dismiss_button" msgid="989567669882005067">"Dismiss"</string>
+ <string name="dialog_continue_button" msgid="8630290044077052145">"Continue"</string>
+ <string name="dialog_sign_in_options_button" msgid="448002958902615054">"Sign-in options"</string>
+ <string name="sign_in_options_title" msgid="6720572645638986680">"Sign-in options"</string>
+ <string name="provider_list_title" msgid="6803918216129492212">"Manage sign-ins"</string>
+ <string name="choose_sign_in_title" msgid="3616025924746872202">"Choose a sign-in"</string>
+ <string name="choose_passkey_title" msgid="8459270617632817465">"Choose passkey"</string>
+ <string name="choose_password_title" msgid="7610721820858017214">"Choose password"</string>
+ <string name="sign_in_on_phone_button" msgid="7618621977586522403">"Sign in on phone"</string>
+ <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="1733094937495140605">"No sign-in info"</string>
+ <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="4320941096211904568">"Tap to unlock"</string>
+</resources>
diff --git a/packages/CredentialManager/wear/res/values-en-rCA/strings.xml b/packages/CredentialManager/wear/res/values-en-rCA/strings.xml
new file mode 100644
index 000000000000..a8a2b7aa7f63
--- /dev/null
+++ b/packages/CredentialManager/wear/res/values-en-rCA/strings.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="7384524142163511792">"Credential Manager"</string>
+ <string name="use_passkey_title" msgid="716598039340757817">"Use passkey?"</string>
+ <string name="use_password_title" msgid="4655101984031246476">"Use password?"</string>
+ <string name="dialog_dismiss_button" msgid="989567669882005067">"Dismiss"</string>
+ <string name="dialog_continue_button" msgid="8630290044077052145">"Continue"</string>
+ <string name="dialog_sign_in_options_button" msgid="448002958902615054">"Sign-in Options"</string>
+ <string name="sign_in_options_title" msgid="6720572645638986680">"Sign-in Options"</string>
+ <string name="provider_list_title" msgid="6803918216129492212">"Manage sign-ins"</string>
+ <string name="choose_sign_in_title" msgid="3616025924746872202">"Choose a sign in"</string>
+ <string name="choose_passkey_title" msgid="8459270617632817465">"Choose passkey"</string>
+ <string name="choose_password_title" msgid="7610721820858017214">"Choose password"</string>
+ <string name="sign_in_on_phone_button" msgid="7618621977586522403">"Sign in on phone"</string>
+ <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="1733094937495140605">"No sign-in info"</string>
+ <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="4320941096211904568">"Tap to unlock"</string>
+</resources>
diff --git a/packages/CredentialManager/wear/res/values-en-rGB/strings.xml b/packages/CredentialManager/wear/res/values-en-rGB/strings.xml
new file mode 100644
index 000000000000..75a0a0067e31
--- /dev/null
+++ b/packages/CredentialManager/wear/res/values-en-rGB/strings.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="7384524142163511792">"Credential Manager"</string>
+ <string name="use_passkey_title" msgid="716598039340757817">"Use passkey?"</string>
+ <string name="use_password_title" msgid="4655101984031246476">"Use password?"</string>
+ <string name="dialog_dismiss_button" msgid="989567669882005067">"Dismiss"</string>
+ <string name="dialog_continue_button" msgid="8630290044077052145">"Continue"</string>
+ <string name="dialog_sign_in_options_button" msgid="448002958902615054">"Sign-in options"</string>
+ <string name="sign_in_options_title" msgid="6720572645638986680">"Sign-in options"</string>
+ <string name="provider_list_title" msgid="6803918216129492212">"Manage sign-ins"</string>
+ <string name="choose_sign_in_title" msgid="3616025924746872202">"Choose a sign-in"</string>
+ <string name="choose_passkey_title" msgid="8459270617632817465">"Choose passkey"</string>
+ <string name="choose_password_title" msgid="7610721820858017214">"Choose password"</string>
+ <string name="sign_in_on_phone_button" msgid="7618621977586522403">"Sign in on phone"</string>
+ <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="1733094937495140605">"No sign-in info"</string>
+ <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="4320941096211904568">"Tap to unlock"</string>
+</resources>
diff --git a/packages/CredentialManager/wear/res/values-en-rIN/strings.xml b/packages/CredentialManager/wear/res/values-en-rIN/strings.xml
new file mode 100644
index 000000000000..75a0a0067e31
--- /dev/null
+++ b/packages/CredentialManager/wear/res/values-en-rIN/strings.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="7384524142163511792">"Credential Manager"</string>
+ <string name="use_passkey_title" msgid="716598039340757817">"Use passkey?"</string>
+ <string name="use_password_title" msgid="4655101984031246476">"Use password?"</string>
+ <string name="dialog_dismiss_button" msgid="989567669882005067">"Dismiss"</string>
+ <string name="dialog_continue_button" msgid="8630290044077052145">"Continue"</string>
+ <string name="dialog_sign_in_options_button" msgid="448002958902615054">"Sign-in options"</string>
+ <string name="sign_in_options_title" msgid="6720572645638986680">"Sign-in options"</string>
+ <string name="provider_list_title" msgid="6803918216129492212">"Manage sign-ins"</string>
+ <string name="choose_sign_in_title" msgid="3616025924746872202">"Choose a sign-in"</string>
+ <string name="choose_passkey_title" msgid="8459270617632817465">"Choose passkey"</string>
+ <string name="choose_password_title" msgid="7610721820858017214">"Choose password"</string>
+ <string name="sign_in_on_phone_button" msgid="7618621977586522403">"Sign in on phone"</string>
+ <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="1733094937495140605">"No sign-in info"</string>
+ <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="4320941096211904568">"Tap to unlock"</string>
+</resources>
diff --git a/packages/CredentialManager/wear/res/values-en-rXC/strings.xml b/packages/CredentialManager/wear/res/values-en-rXC/strings.xml
new file mode 100644
index 000000000000..fbdd5cfff1dc
--- /dev/null
+++ b/packages/CredentialManager/wear/res/values-en-rXC/strings.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="7384524142163511792">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‏‏‏‏‎‏‎‏‏‏‏‏‏‏‏‎‎‏‏‎‎‏‏‏‏‎‏‏‎‎‎‏‏‎‎‏‏‎‎‏‎‏‎‏‎‎‎‏‏‎‎‎‏‏‏‏‎‎‏‏‏‏‎‎‏‎‎‏‏‏‏‏‎‎‎‎‎Credential Manager‎‏‎‎‏‎"</string>
+ <string name="use_passkey_title" msgid="716598039340757817">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‏‏‏‏‎‏‎‏‏‏‏‎‎‏‎‎‏‏‏‏‏‎‎‎‏‏‏‎‏‏‏‏‎‎‎‎‏‏‏‏‎‏‎‏‏‏‏‎‏‏‎‏‎‎‏‎‏‏‎‏‏‎‎‏‏‎‎‏‏‏‎‎‏‎Use passkey?‎‏‎‎‏‎"</string>
+ <string name="use_password_title" msgid="4655101984031246476">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‏‏‏‏‎‏‎‏‏‏‏‏‏‏‎‎‎‎‎‎‏‎‎‏‏‎‏‎‎‎‏‏‏‏‏‎‏‎‎‏‎‏‏‏‎‎‏‏‎‏‏‏‎‏‏‎‎‏‏‎‎‎‎‎‏‎‎‎‏‎‎‎‏‏‎‎‎Use password?‎‏‎‎‏‎"</string>
+ <string name="dialog_dismiss_button" msgid="989567669882005067">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‏‏‏‏‎‏‎‏‏‏‏‎‎‏‏‎‏‏‎‏‏‏‎‏‏‏‎‏‎‎‏‏‎‏‎‎‎‏‏‎‏‏‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‎‎‏‎‎‏‏‎‎‏‎‎‏‎‏‏‎Dismiss‎‏‎‎‏‎"</string>
+ <string name="dialog_continue_button" msgid="8630290044077052145">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‏‏‏‏‎‏‎‏‏‏‏‏‏‏‏‏‎‏‏‏‏‏‎‎‎‏‎‎‏‏‏‏‎‎‏‏‎‎‎‏‎‎‎‏‏‏‏‎‎‎‎‏‏‏‎‎‏‏‎‏‏‎‎‏‎‎‎‎‏‏‏‏‎‎‎‏‎Continue‎‏‎‎‏‎"</string>
+ <string name="dialog_sign_in_options_button" msgid="448002958902615054">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‏‏‏‏‎‏‎‏‏‏‎‏‏‏‏‎‎‎‏‏‎‏‏‏‏‎‏‎‎‎‎‎‎‏‎‏‎‎‎‏‎‏‎‎‎‏‏‏‏‎‏‏‎‏‏‎‏‏‎‏‏‏‎‎‎‎‎‎‏‏‏‎‎Sign-in Options‎‏‎‎‏‎"</string>
+ <string name="sign_in_options_title" msgid="6720572645638986680">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‏‏‏‏‎‏‎‏‏‏‏‏‏‏‎‏‏‏‎‏‎‏‎‎‎‏‎‎‎‏‎‎‎‏‎‏‎‎‏‏‎‏‏‎‏‏‎‎‏‏‏‎‏‎‎‎‎‏‎‎‏‏‎‏‏‎‏‏‏‎‏‏‏‎‎‎‎Sign-in Options‎‏‎‎‏‎"</string>
+ <string name="provider_list_title" msgid="6803918216129492212">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‏‏‏‏‎‏‎‏‏‏‏‏‏‏‎‏‏‏‏‎‎‏‏‎‏‏‎‎‎‏‎‏‏‏‏‏‏‎‎‏‎‎‎‏‏‎‏‎‎‎‎‏‎‎‏‏‎‏‎‏‎‎‏‏‎‏‎‎‏‏‏‏‎‏‎‎‎Manage sign-ins‎‏‎‎‏‎"</string>
+ <string name="choose_sign_in_title" msgid="3616025924746872202">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‏‏‏‏‎‏‎‏‏‏‏‏‎‏‏‎‎‏‎‎‎‏‎‏‏‏‎‏‎‏‏‎‏‎‎‎‏‏‎‏‎‏‏‏‎‎‎‎‏‏‏‎‎‏‎‎‏‎‎‎‎‎‎‎‏‎‏‏‎‎‎‏‎‏‎‎Choose a sign in‎‏‎‎‏‎"</string>
+ <string name="choose_passkey_title" msgid="8459270617632817465">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‏‏‏‏‎‏‎‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‏‎‎‏‎‏‎‏‎‏‏‏‎‏‏‏‎‎‏‏‏‎‏‎‏‏‏‏‏‎‏‏‏‎‎‏‏‏‎‏‎‎‎‎‎‏‎‎‏‏‏‎‎‏‎Choose passkey‎‏‎‎‏‎"</string>
+ <string name="choose_password_title" msgid="7610721820858017214">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‏‏‏‏‎‏‎‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‎‏‏‏‏‎‏‎‏‏‎‏‏‏‎‎‏‎‏‏‎‎‎‎‏‏‏‎‎‎‏‎‎‎‏‏‏‎‎‏‏‎‎‏‎‏‏‎‏‏‏‏‏‎‎Choose password‎‏‎‎‏‎"</string>
+ <string name="sign_in_on_phone_button" msgid="7618621977586522403">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‏‏‏‏‎‏‎‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‏‏‏‎‏‎‏‏‎‎‏‎‎‎‎‏‎‏‎‎‏‎‏‏‎‎‏‏‎‎‎‎‎‎‎‏‏‏‎‏‎‏‏‎‎‏‎‎‏‎‎‎‏‏‎Sign in on phone‎‏‎‎‏‎"</string>
+ <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="1733094937495140605">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‏‏‏‏‎‏‎‏‏‏‏‎‏‏‏‎‎‎‎‎‎‎‏‏‎‏‎‎‏‏‎‎‎‎‏‎‏‎‏‎‎‏‏‏‎‎‏‏‏‏‎‏‏‎‏‏‎‎‏‏‏‏‏‎‎‎‏‏‏‏‏‏‎‏‎No sign-in info‎‏‎‎‏‎"</string>
+ <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="4320941096211904568">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‏‏‏‏‎‏‎‏‏‏‏‏‎‏‏‏‎‏‏‏‏‏‏‎‏‏‏‎‎‎‏‎‎‎‏‎‎‎‎‏‎‎‎‏‎‎‏‏‏‏‏‎‎‎‏‏‎‎‎‏‏‏‏‏‎‎‎‎‎‏‏‏‎‎‎‎Tap to unlock‎‏‎‎‏‎"</string>
+</resources>
diff --git a/packages/CredentialManager/wear/res/values-es-rUS/strings.xml b/packages/CredentialManager/wear/res/values-es-rUS/strings.xml
new file mode 100644
index 000000000000..97bb3e056ec8
--- /dev/null
+++ b/packages/CredentialManager/wear/res/values-es-rUS/strings.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="7384524142163511792">"Credential Manager"</string>
+ <string name="use_passkey_title" msgid="716598039340757817">"¿Quieres usar una llave de acceso?"</string>
+ <string name="use_password_title" msgid="4655101984031246476">"¿Quieres usar una contraseña?"</string>
+ <string name="dialog_dismiss_button" msgid="989567669882005067">"Descartar"</string>
+ <string name="dialog_continue_button" msgid="8630290044077052145">"Continuar"</string>
+ <string name="dialog_sign_in_options_button" msgid="448002958902615054">"Opción para acceder"</string>
+ <string name="sign_in_options_title" msgid="6720572645638986680">"Opción para acceder"</string>
+ <string name="provider_list_title" msgid="6803918216129492212">"Administrar accesos"</string>
+ <string name="choose_sign_in_title" msgid="3616025924746872202">"Elige un acceso"</string>
+ <string name="choose_passkey_title" msgid="8459270617632817465">"Elige una llave de acceso"</string>
+ <string name="choose_password_title" msgid="7610721820858017214">"Elige una contraseña"</string>
+ <string name="sign_in_on_phone_button" msgid="7618621977586522403">"Acceder desde el teléfono"</string>
+ <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="1733094937495140605">"No hay información de acceso"</string>
+ <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="4320941096211904568">"Presiona para desbloquear"</string>
+</resources>
diff --git a/packages/CredentialManager/wear/res/values-fi/strings.xml b/packages/CredentialManager/wear/res/values-fi/strings.xml
new file mode 100644
index 000000000000..855f025e1b81
--- /dev/null
+++ b/packages/CredentialManager/wear/res/values-fi/strings.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="7384524142163511792">"Kirjautumistietojen hallinta"</string>
+ <string name="use_passkey_title" msgid="716598039340757817">"Käytetäänkö avainkoodia?"</string>
+ <string name="use_password_title" msgid="4655101984031246476">"Käytetäänkö salasanaa?"</string>
+ <string name="dialog_dismiss_button" msgid="989567669882005067">"Hylkää"</string>
+ <string name="dialog_continue_button" msgid="8630290044077052145">"Jatka"</string>
+ <string name="dialog_sign_in_options_button" msgid="448002958902615054">"Kirjautumisvaihtoehdot"</string>
+ <string name="sign_in_options_title" msgid="6720572645638986680">"Kirjautumisvaihtoehdot"</string>
+ <string name="provider_list_title" msgid="6803918216129492212">"Muuta kirjautumistietoja"</string>
+ <string name="choose_sign_in_title" msgid="3616025924746872202">"Valitse kirjautumistapa"</string>
+ <string name="choose_passkey_title" msgid="8459270617632817465">"Valitse avainkoodi"</string>
+ <string name="choose_password_title" msgid="7610721820858017214">"Valitse salasana"</string>
+ <string name="sign_in_on_phone_button" msgid="7618621977586522403">"Kirjaudu sisään puhelimella"</string>
+ <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="1733094937495140605">"Ei kirjautumistietoja"</string>
+ <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="4320941096211904568">"Avaa napauttamalla"</string>
+</resources>
diff --git a/packages/CredentialManager/wear/res/values-gu/strings.xml b/packages/CredentialManager/wear/res/values-gu/strings.xml
new file mode 100644
index 000000000000..ff8d2989253a
--- /dev/null
+++ b/packages/CredentialManager/wear/res/values-gu/strings.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="7384524142163511792">"લૉગ ઇન વિગતોના મેનેજર"</string>
+ <string name="use_passkey_title" msgid="716598039340757817">"પાસકીનો ઉપયોગ કરીએ?"</string>
+ <string name="use_password_title" msgid="4655101984031246476">"પાસવર્ડનો ઉપયોગ કરીએ?"</string>
+ <string name="dialog_dismiss_button" msgid="989567669882005067">"છોડી દો"</string>
+ <string name="dialog_continue_button" msgid="8630290044077052145">"ચાલુ રાખો"</string>
+ <string name="dialog_sign_in_options_button" msgid="448002958902615054">"સાઇન-ઇનના વિકલ્પો"</string>
+ <string name="sign_in_options_title" msgid="6720572645638986680">"સાઇન-ઇનના વિકલ્પો"</string>
+ <string name="provider_list_title" msgid="6803918216129492212">"સાઇન-ઇન મેનેજ કરો"</string>
+ <string name="choose_sign_in_title" msgid="3616025924746872202">"સાઇન ઇન કરવાની કોઈ રીત પસંદ કરો"</string>
+ <string name="choose_passkey_title" msgid="8459270617632817465">"પાસકી પસંદ કરો"</string>
+ <string name="choose_password_title" msgid="7610721820858017214">"પાસવર્ડ પસંદ કરો"</string>
+ <string name="sign_in_on_phone_button" msgid="7618621977586522403">"ફોન પર સાઇન ઇન કરો"</string>
+ <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="1733094937495140605">"કોઈ સાઇન-ઇન માહિતી નથી"</string>
+ <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="4320941096211904568">"અનલૉક કરવા માટે ટૅપ કરો"</string>
+</resources>
diff --git a/packages/CredentialManager/wear/res/values-hi/strings.xml b/packages/CredentialManager/wear/res/values-hi/strings.xml
new file mode 100644
index 000000000000..a061453e72a4
--- /dev/null
+++ b/packages/CredentialManager/wear/res/values-hi/strings.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="7384524142163511792">"Credential Manager"</string>
+ <string name="use_passkey_title" msgid="716598039340757817">"क्या आपको पासकी का इस्तेमाल करना है?"</string>
+ <string name="use_password_title" msgid="4655101984031246476">"क्या आपको पासवर्ड का इस्तेमाल करना है?"</string>
+ <string name="dialog_dismiss_button" msgid="989567669882005067">"खारिज करें"</string>
+ <string name="dialog_continue_button" msgid="8630290044077052145">"जारी रखें"</string>
+ <string name="dialog_sign_in_options_button" msgid="448002958902615054">"साइन इन करने के विकल्प"</string>
+ <string name="sign_in_options_title" msgid="6720572645638986680">"साइन इन करने के विकल्प"</string>
+ <string name="provider_list_title" msgid="6803918216129492212">"साइन-इन क्रेडेंशियल मैनेज करें"</string>
+ <string name="choose_sign_in_title" msgid="3616025924746872202">"साइन इन करने का कोई तरीका चुनें"</string>
+ <string name="choose_passkey_title" msgid="8459270617632817465">"कोई पासकी चुनें"</string>
+ <string name="choose_password_title" msgid="7610721820858017214">"कोई पासवर्ड चुनें"</string>
+ <string name="sign_in_on_phone_button" msgid="7618621977586522403">"फ़ोन पर साइन इन करें"</string>
+ <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="1733094937495140605">"साइन-इन के लिए कोई क्रेडेंशियल मौजूद नहीं है"</string>
+ <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="4320941096211904568">"अनलॉक करने के लिए टैप करें"</string>
+</resources>
diff --git a/packages/CredentialManager/wear/res/values-hy/strings.xml b/packages/CredentialManager/wear/res/values-hy/strings.xml
new file mode 100644
index 000000000000..cea111294f36
--- /dev/null
+++ b/packages/CredentialManager/wear/res/values-hy/strings.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="7384524142163511792">"Մուտքի տվյալների կառավարիչ"</string>
+ <string name="use_passkey_title" msgid="716598039340757817">"Օգտագործե՞լ մուտքի բանալին"</string>
+ <string name="use_password_title" msgid="4655101984031246476">"Օգտագործե՞լ գաղտնաբառը"</string>
+ <string name="dialog_dismiss_button" msgid="989567669882005067">"Փակել"</string>
+ <string name="dialog_continue_button" msgid="8630290044077052145">"Շարունակել"</string>
+ <string name="dialog_sign_in_options_button" msgid="448002958902615054">"Մուտք գործելու եղանակներ"</string>
+ <string name="sign_in_options_title" msgid="6720572645638986680">"Մուտք գործելու եղանակներ"</string>
+ <string name="provider_list_title" msgid="6803918216129492212">"Մուտքի կառավարում"</string>
+ <string name="choose_sign_in_title" msgid="3616025924746872202">"Ընտրեք մուտք գործելու եղանակը"</string>
+ <string name="choose_passkey_title" msgid="8459270617632817465">"Ընտրեք մուտքի բանալին"</string>
+ <string name="choose_password_title" msgid="7610721820858017214">"Ընտրեք գաղտնաբառը"</string>
+ <string name="sign_in_on_phone_button" msgid="7618621977586522403">"Մուտք գործել հեռախոսում"</string>
+ <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="1733094937495140605">"Մուտքի տվյալներ չկան"</string>
+ <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="4320941096211904568">"Հպեք ապակողպելու համար"</string>
+</resources>
diff --git a/packages/CredentialManager/wear/res/values-is/strings.xml b/packages/CredentialManager/wear/res/values-is/strings.xml
new file mode 100644
index 000000000000..fcd9ce59ee9d
--- /dev/null
+++ b/packages/CredentialManager/wear/res/values-is/strings.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="7384524142163511792">"Skilríkjastjórnun"</string>
+ <string name="use_passkey_title" msgid="716598039340757817">"Nota aðgangslykil?"</string>
+ <string name="use_password_title" msgid="4655101984031246476">"Nota aðgangsorð?"</string>
+ <string name="dialog_dismiss_button" msgid="989567669882005067">"Hunsa"</string>
+ <string name="dialog_continue_button" msgid="8630290044077052145">"Halda áfram"</string>
+ <string name="dialog_sign_in_options_button" msgid="448002958902615054">"Innskráningarkostir"</string>
+ <string name="sign_in_options_title" msgid="6720572645638986680">"Innskráningarkostir"</string>
+ <string name="provider_list_title" msgid="6803918216129492212">"Stjórna innskráningu"</string>
+ <string name="choose_sign_in_title" msgid="3616025924746872202">"Velja innskráningu"</string>
+ <string name="choose_passkey_title" msgid="8459270617632817465">"Velja aðgangslykil"</string>
+ <string name="choose_password_title" msgid="7610721820858017214">"Velja aðgangsorð"</string>
+ <string name="sign_in_on_phone_button" msgid="7618621977586522403">"Skráðu þig inn á síma"</string>
+ <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="1733094937495140605">"Engar innskráningarupplýsingar"</string>
+ <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="4320941096211904568">"Ýttu til að opna"</string>
+</resources>
diff --git a/packages/CredentialManager/wear/res/values-ja/strings.xml b/packages/CredentialManager/wear/res/values-ja/strings.xml
new file mode 100644
index 000000000000..05a04e32a94d
--- /dev/null
+++ b/packages/CredentialManager/wear/res/values-ja/strings.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="7384524142163511792">"認証情報マネージャー"</string>
+ <string name="use_passkey_title" msgid="716598039340757817">"パスキーを使用しますか?"</string>
+ <string name="use_password_title" msgid="4655101984031246476">"パスワードを使用しますか?"</string>
+ <string name="dialog_dismiss_button" msgid="989567669882005067">"閉じる"</string>
+ <string name="dialog_continue_button" msgid="8630290044077052145">"続行"</string>
+ <string name="dialog_sign_in_options_button" msgid="448002958902615054">"ログイン オプション"</string>
+ <string name="sign_in_options_title" msgid="6720572645638986680">"ログイン オプション"</string>
+ <string name="provider_list_title" msgid="6803918216129492212">"ログインの管理"</string>
+ <string name="choose_sign_in_title" msgid="3616025924746872202">"ログインの選択"</string>
+ <string name="choose_passkey_title" msgid="8459270617632817465">"パスキーの選択"</string>
+ <string name="choose_password_title" msgid="7610721820858017214">"パスワードの選択"</string>
+ <string name="sign_in_on_phone_button" msgid="7618621977586522403">"スマートフォンでログイン"</string>
+ <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="1733094937495140605">"ログイン情報はありません"</string>
+ <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="4320941096211904568">"タップしてロック解除"</string>
+</resources>
diff --git a/packages/CredentialManager/wear/res/values-ka/strings.xml b/packages/CredentialManager/wear/res/values-ka/strings.xml
new file mode 100644
index 000000000000..2164d1ec7f6a
--- /dev/null
+++ b/packages/CredentialManager/wear/res/values-ka/strings.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="7384524142163511792">"ავტორიზაციის მონაცემების მმართველი"</string>
+ <string name="use_passkey_title" msgid="716598039340757817">"გსურთ წვდომის გასაღების გამოყენება?"</string>
+ <string name="use_password_title" msgid="4655101984031246476">"გსურთ პაროლის გამოყენება?"</string>
+ <string name="dialog_dismiss_button" msgid="989567669882005067">"დახურვა"</string>
+ <string name="dialog_continue_button" msgid="8630290044077052145">"გაგრძელება"</string>
+ <string name="dialog_sign_in_options_button" msgid="448002958902615054">"სისტემაში შესვლის ვარიანტები"</string>
+ <string name="sign_in_options_title" msgid="6720572645638986680">"სისტემაში შესვლის ვარიანტები"</string>
+ <string name="provider_list_title" msgid="6803918216129492212">"სისტემაში შესვლის მართვა"</string>
+ <string name="choose_sign_in_title" msgid="3616025924746872202">"სისტემაში შესვლის არჩევა"</string>
+ <string name="choose_passkey_title" msgid="8459270617632817465">"წვდომის გასაღების არჩევა"</string>
+ <string name="choose_password_title" msgid="7610721820858017214">"პაროლის არჩევა"</string>
+ <string name="sign_in_on_phone_button" msgid="7618621977586522403">"სისტემაში შესვლა ტელეფონით"</string>
+ <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="1733094937495140605">"სისტემაში შესვლისთვის ინფორმაცია არ არის"</string>
+ <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="4320941096211904568">"შეეხეთ განსაბლოკად"</string>
+</resources>
diff --git a/packages/CredentialManager/wear/res/values-km/strings.xml b/packages/CredentialManager/wear/res/values-km/strings.xml
new file mode 100644
index 000000000000..9dcaeb87c891
--- /dev/null
+++ b/packages/CredentialManager/wear/res/values-km/strings.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="7384524142163511792">"Credential Manager"</string>
+ <string name="use_passkey_title" msgid="716598039340757817">"ប្រើកូដសម្ងាត់ឬ?"</string>
+ <string name="use_password_title" msgid="4655101984031246476">"ប្រើពាក្យ​សម្ងាត់ឬ?"</string>
+ <string name="dialog_dismiss_button" msgid="989567669882005067">"ច្រានចោល"</string>
+ <string name="dialog_continue_button" msgid="8630290044077052145">"បន្ត"</string>
+ <string name="dialog_sign_in_options_button" msgid="448002958902615054">"ជម្រើសចូលគណនី"</string>
+ <string name="sign_in_options_title" msgid="6720572645638986680">"ជម្រើសចូលគណនី"</string>
+ <string name="provider_list_title" msgid="6803918216129492212">"គ្រប់គ្រងការចូល​គណនី"</string>
+ <string name="choose_sign_in_title" msgid="3616025924746872202">"ជ្រើសរើសការចូល​គណនី"</string>
+ <string name="choose_passkey_title" msgid="8459270617632817465">"ជ្រើសរើសកូដសម្ងាត់"</string>
+ <string name="choose_password_title" msgid="7610721820858017214">"ជ្រើសរើសពាក្យ​សម្ងាត់"</string>
+ <string name="sign_in_on_phone_button" msgid="7618621977586522403">"ចូលនៅលើទូរសព្ទ"</string>
+ <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="1733094937495140605">"គ្មានព័ត៌មានចូលគណនីទេ"</string>
+ <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="4320941096211904568">"ចុចដើម្បីដោះសោ"</string>
+</resources>
diff --git a/packages/CredentialManager/wear/res/values-kn/strings.xml b/packages/CredentialManager/wear/res/values-kn/strings.xml
new file mode 100644
index 000000000000..fc2f65eecf22
--- /dev/null
+++ b/packages/CredentialManager/wear/res/values-kn/strings.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="7384524142163511792">"ಕ್ರೆಡೆನ್ಶಿಯಲ್ ಮ್ಯಾನೇಜರ್"</string>
+ <string name="use_passkey_title" msgid="716598039340757817">"ಪಾಸ್‌ಕೀ ಅನ್ನು ಬಳಸಬೇಕೆ?"</string>
+ <string name="use_password_title" msgid="4655101984031246476">"ಪಾಸ್‌ವರ್ಡ್ ಅನ್ನು ಬಳಸಬೇಕೆ?"</string>
+ <string name="dialog_dismiss_button" msgid="989567669882005067">"ವಜಾಗೊಳಿಸಿ"</string>
+ <string name="dialog_continue_button" msgid="8630290044077052145">"ಮುಂದುವರಿಸಿ"</string>
+ <string name="dialog_sign_in_options_button" msgid="448002958902615054">"ಸೈನ್ ಇನ್ ಆಯ್ಕೆಗಳು"</string>
+ <string name="sign_in_options_title" msgid="6720572645638986680">"ಸೈನ್ ಇನ್ ಆಯ್ಕೆಗಳು"</string>
+ <string name="provider_list_title" msgid="6803918216129492212">"ಸೈನ್-ಇನ್‌ಗಳನ್ನು ನಿರ್ವಹಿಸಿ"</string>
+ <string name="choose_sign_in_title" msgid="3616025924746872202">"ಸೈನ್-ಇನ್ ಅನ್ನು ಆರಿಸಿ"</string>
+ <string name="choose_passkey_title" msgid="8459270617632817465">"ಪಾಸ್‌ಕೀ ಅನ್ನು ಆರಿಸಿ"</string>
+ <string name="choose_password_title" msgid="7610721820858017214">"ಪಾಸ್‌ವರ್ಡ್ ಅನ್ನು ಆರಿಸಿ"</string>
+ <string name="sign_in_on_phone_button" msgid="7618621977586522403">"ಫೋನ್‌ನಲ್ಲಿ ಸೈನ್ ಇನ್ ಮಾಡಿ"</string>
+ <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="1733094937495140605">"ಯಾವುದೇ ಸೈನ್ ಇನ್ ಮಾಹಿತಿಯಿಲ್ಲ"</string>
+ <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="4320941096211904568">"ಅನ್‌ಲಾಕ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
+</resources>
diff --git a/packages/CredentialManager/wear/res/values-ko/strings.xml b/packages/CredentialManager/wear/res/values-ko/strings.xml
new file mode 100644
index 000000000000..a07fb2ab6e21
--- /dev/null
+++ b/packages/CredentialManager/wear/res/values-ko/strings.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="7384524142163511792">"인증 관리자"</string>
+ <string name="use_passkey_title" msgid="716598039340757817">"패스키를 사용하시겠습니까?"</string>
+ <string name="use_password_title" msgid="4655101984031246476">"비밀번호를 사용하시겠습니까?"</string>
+ <string name="dialog_dismiss_button" msgid="989567669882005067">"닫기"</string>
+ <string name="dialog_continue_button" msgid="8630290044077052145">"계속"</string>
+ <string name="dialog_sign_in_options_button" msgid="448002958902615054">"로그인 옵션"</string>
+ <string name="sign_in_options_title" msgid="6720572645638986680">"로그인 옵션"</string>
+ <string name="provider_list_title" msgid="6803918216129492212">"로그인 정보 관리"</string>
+ <string name="choose_sign_in_title" msgid="3616025924746872202">"로그인 선택"</string>
+ <string name="choose_passkey_title" msgid="8459270617632817465">"패스키 선택"</string>
+ <string name="choose_password_title" msgid="7610721820858017214">"비밀번호 선택"</string>
+ <string name="sign_in_on_phone_button" msgid="7618621977586522403">"휴대전화에서 로그인하기"</string>
+ <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="1733094937495140605">"로그인 정보 없음"</string>
+ <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="4320941096211904568">"탭하여 잠금 해제하기"</string>
+</resources>
diff --git a/packages/CredentialManager/wear/res/values-lo/strings.xml b/packages/CredentialManager/wear/res/values-lo/strings.xml
new file mode 100644
index 000000000000..c48f88fa921e
--- /dev/null
+++ b/packages/CredentialManager/wear/res/values-lo/strings.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="7384524142163511792">"ຕົວຈັດການຂໍ້ມູນການເຂົ້າສູ່ລະບົບ"</string>
+ <string name="use_passkey_title" msgid="716598039340757817">"ໃຊ້ກະແຈຜ່ານບໍ?"</string>
+ <string name="use_password_title" msgid="4655101984031246476">"ໃຊ້ລະຫັດຜ່ານບໍ?"</string>
+ <string name="dialog_dismiss_button" msgid="989567669882005067">"ປິດໄວ້"</string>
+ <string name="dialog_continue_button" msgid="8630290044077052145">"ສືບຕໍ່"</string>
+ <string name="dialog_sign_in_options_button" msgid="448002958902615054">"ຕົວເລືອກການເຂົ້າສູ່ລະບົບ"</string>
+ <string name="sign_in_options_title" msgid="6720572645638986680">"ຕົວເລືອກການເຂົ້າສູ່ລະບົບ"</string>
+ <string name="provider_list_title" msgid="6803918216129492212">"ຈັດການການເຂົ້າສູ່ລະບົບ"</string>
+ <string name="choose_sign_in_title" msgid="3616025924746872202">"ເລືອກການເຂົ້າສູ່ລະບົບ"</string>
+ <string name="choose_passkey_title" msgid="8459270617632817465">"ເລືອກກະແຈຜ່ານ"</string>
+ <string name="choose_password_title" msgid="7610721820858017214">"ເລືອກລະຫັດຜ່ານ"</string>
+ <string name="sign_in_on_phone_button" msgid="7618621977586522403">"ເຂົ້າສູ່ລະບົບຢູ່ໂທລະສັບ"</string>
+ <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="1733094937495140605">"ບໍ່ມີຂໍ້ມູນການເຂົ້າສູ່ລະບົບ"</string>
+ <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="4320941096211904568">"ແຕະເພື່ອປົດລັອກ"</string>
+</resources>
diff --git a/packages/CredentialManager/wear/res/values-ml/strings.xml b/packages/CredentialManager/wear/res/values-ml/strings.xml
new file mode 100644
index 000000000000..a93514809c57
--- /dev/null
+++ b/packages/CredentialManager/wear/res/values-ml/strings.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="7384524142163511792">"ക്രെഡൻഷ്യൽ മാനേജർ"</string>
+ <string name="use_passkey_title" msgid="716598039340757817">"പാസ്‌കീ ഉപയോഗിക്കുക"</string>
+ <string name="use_password_title" msgid="4655101984031246476">"പാസ്‌വേഡ് ഉപയോഗിക്കണോ?"</string>
+ <string name="dialog_dismiss_button" msgid="989567669882005067">"ഡിസ്‌മിസ് ചെയ്യുക"</string>
+ <string name="dialog_continue_button" msgid="8630290044077052145">"തുടരുക"</string>
+ <string name="dialog_sign_in_options_button" msgid="448002958902615054">"സൈൻ ഇൻ ചെയ്യൽ ഓപ്ഷനുകൾ"</string>
+ <string name="sign_in_options_title" msgid="6720572645638986680">"സൈൻ ഇൻ ചെയ്യൽ ഓപ്ഷനുകൾ"</string>
+ <string name="provider_list_title" msgid="6803918216129492212">"സൈൻ ഇൻ ചെയ്യലുകൾ മാനേജ് ചെയ്യുക"</string>
+ <string name="choose_sign_in_title" msgid="3616025924746872202">"ഒരു സൈൻ-ഇൻ തിരഞ്ഞെടുക്കുക"</string>
+ <string name="choose_passkey_title" msgid="8459270617632817465">"പാസ്‌കീ തിരഞ്ഞെടുക്കുക"</string>
+ <string name="choose_password_title" msgid="7610721820858017214">"പാസ്‌കീ തിരഞ്ഞെടുക്കുക"</string>
+ <string name="sign_in_on_phone_button" msgid="7618621977586522403">"ഫോണിൽ സൈൻ ഇൻ ചെയ്യുക"</string>
+ <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="1733094937495140605">"സൈൻ ഇൻ വിവരങ്ങളൊന്നുമില്ല"</string>
+ <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="4320941096211904568">"അൺലോക്ക് ചെയ്യാൻ ടാപ്പ് ചെയ്യുക"</string>
+</resources>
diff --git a/packages/CredentialManager/wear/res/values-mr/strings.xml b/packages/CredentialManager/wear/res/values-mr/strings.xml
new file mode 100644
index 000000000000..e966d308ec21
--- /dev/null
+++ b/packages/CredentialManager/wear/res/values-mr/strings.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="7384524142163511792">"क्रेडेंशियल व्यवस्थापक"</string>
+ <string name="use_passkey_title" msgid="716598039340757817">"पासकी वापरायची आहे का?"</string>
+ <string name="use_password_title" msgid="4655101984031246476">"पासवर्ड वापरायचा आहे का?"</string>
+ <string name="dialog_dismiss_button" msgid="989567669882005067">"डिसमिस करा"</string>
+ <string name="dialog_continue_button" msgid="8630290044077052145">"पुढे सुरू ठेवा"</string>
+ <string name="dialog_sign_in_options_button" msgid="448002958902615054">"साइन-इन पर्याय"</string>
+ <string name="sign_in_options_title" msgid="6720572645638986680">"साइन-इन पर्याय"</string>
+ <string name="provider_list_title" msgid="6803918216129492212">"साइन-इन व्यवस्थापित करा"</string>
+ <string name="choose_sign_in_title" msgid="3616025924746872202">"साइन इन निवडा"</string>
+ <string name="choose_passkey_title" msgid="8459270617632817465">"पासकी निवडा"</string>
+ <string name="choose_password_title" msgid="7610721820858017214">"पासवर्ड निवडा"</string>
+ <string name="sign_in_on_phone_button" msgid="7618621977586522403">"फोनवर साइन इन करा"</string>
+ <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="1733094937495140605">"साइन-इनची कोणतीही माहिती नाही"</string>
+ <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="4320941096211904568">"अनलॉक करण्यासाठी टॅप करा"</string>
+</resources>
diff --git a/packages/CredentialManager/wear/res/values-ms/strings.xml b/packages/CredentialManager/wear/res/values-ms/strings.xml
new file mode 100644
index 000000000000..772bf194c77c
--- /dev/null
+++ b/packages/CredentialManager/wear/res/values-ms/strings.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="7384524142163511792">"Pengurus Bukti Kelayakan"</string>
+ <string name="use_passkey_title" msgid="716598039340757817">"Gunakan kunci laluan?"</string>
+ <string name="use_password_title" msgid="4655101984031246476">"Gunakan kata laluan?"</string>
+ <string name="dialog_dismiss_button" msgid="989567669882005067">"Ketepikan"</string>
+ <string name="dialog_continue_button" msgid="8630290044077052145">"Teruskan"</string>
+ <string name="dialog_sign_in_options_button" msgid="448002958902615054">"Pilihan Log Masuk"</string>
+ <string name="sign_in_options_title" msgid="6720572645638986680">"Pilihan Log Masuk"</string>
+ <string name="provider_list_title" msgid="6803918216129492212">"Urus log masuk"</string>
+ <string name="choose_sign_in_title" msgid="3616025924746872202">"Pilih log masuk"</string>
+ <string name="choose_passkey_title" msgid="8459270617632817465">"Pilih kunci laluan"</string>
+ <string name="choose_password_title" msgid="7610721820858017214">"Pilih kata laluan"</string>
+ <string name="sign_in_on_phone_button" msgid="7618621977586522403">"Log masuk pada telefon"</string>
+ <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="1733094937495140605">"Tiada maklumat log masuk"</string>
+ <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="4320941096211904568">"Ketik untuk membuka kunci"</string>
+</resources>
diff --git a/packages/CredentialManager/wear/res/values-my/strings.xml b/packages/CredentialManager/wear/res/values-my/strings.xml
new file mode 100644
index 000000000000..7c38b9ef40a8
--- /dev/null
+++ b/packages/CredentialManager/wear/res/values-my/strings.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="7384524142163511792">"Credential Manager"</string>
+ <string name="use_passkey_title" msgid="716598039340757817">"လျှို့ဝှက်ကီး သုံးမလား။"</string>
+ <string name="use_password_title" msgid="4655101984031246476">"စကားဝှက် သုံးမလား။"</string>
+ <string name="dialog_dismiss_button" msgid="989567669882005067">"ပယ်ရန်"</string>
+ <string name="dialog_continue_button" msgid="8630290044077052145">"ရှေ့ဆက်ရန်"</string>
+ <string name="dialog_sign_in_options_button" msgid="448002958902615054">"လက်မှတ်ထိုးဝင်နည်းများ"</string>
+ <string name="sign_in_options_title" msgid="6720572645638986680">"လက်မှတ်ထိုးဝင်နည်းများ"</string>
+ <string name="provider_list_title" msgid="6803918216129492212">"လက်မှတ်ထိုးဝင်မှုများ စီမံခြင်း"</string>
+ <string name="choose_sign_in_title" msgid="3616025924746872202">"လက်မှတ်ထိုးဝင်မှု ရွေးခြင်း"</string>
+ <string name="choose_passkey_title" msgid="8459270617632817465">"လျှို့ဝှက်ကီးရွေးခြင်း"</string>
+ <string name="choose_password_title" msgid="7610721820858017214">"စကားဝှက်ရွေးခြင်း"</string>
+ <string name="sign_in_on_phone_button" msgid="7618621977586522403">"ဖုန်းတွင် လက်မှတ်ထိုးဝင်ရန်"</string>
+ <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="1733094937495140605">"လက်မှတ်ထိုးဝင်ရန် အချက်အလက် မရှိပါ"</string>
+ <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="4320941096211904568">"ဖွင့်ရန် တို့ပါ"</string>
+</resources>
diff --git a/packages/CredentialManager/wear/res/values-nb/strings.xml b/packages/CredentialManager/wear/res/values-nb/strings.xml
new file mode 100644
index 000000000000..0c45c9cdb30a
--- /dev/null
+++ b/packages/CredentialManager/wear/res/values-nb/strings.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="7384524142163511792">"Legitimasjonsbehandling"</string>
+ <string name="use_passkey_title" msgid="716598039340757817">"Vil du bruke passnøkkel?"</string>
+ <string name="use_password_title" msgid="4655101984031246476">"Vil du bruke passord?"</string>
+ <string name="dialog_dismiss_button" msgid="989567669882005067">"Lukk"</string>
+ <string name="dialog_continue_button" msgid="8630290044077052145">"Fortsett"</string>
+ <string name="dialog_sign_in_options_button" msgid="448002958902615054">"Påloggingsalternativer"</string>
+ <string name="sign_in_options_title" msgid="6720572645638986680">"Påloggingsalternativer"</string>
+ <string name="provider_list_title" msgid="6803918216129492212">"Administrer pålogginger"</string>
+ <string name="choose_sign_in_title" msgid="3616025924746872202">"Velg en pålogging"</string>
+ <string name="choose_passkey_title" msgid="8459270617632817465">"Velg passnøkkel"</string>
+ <string name="choose_password_title" msgid="7610721820858017214">"Velg passord"</string>
+ <string name="sign_in_on_phone_button" msgid="7618621977586522403">"Logg på med telefonen"</string>
+ <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="1733094937495140605">"Ingen påloggingsinformasjon"</string>
+ <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="4320941096211904568">"Trykk for å låse opp"</string>
+</resources>
diff --git a/packages/CredentialManager/wear/res/values-nl/strings.xml b/packages/CredentialManager/wear/res/values-nl/strings.xml
new file mode 100644
index 000000000000..1a15ead6abd2
--- /dev/null
+++ b/packages/CredentialManager/wear/res/values-nl/strings.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="7384524142163511792">"Manager Inloggegevens"</string>
+ <string name="use_passkey_title" msgid="716598039340757817">"Toegangssleutel gebruiken?"</string>
+ <string name="use_password_title" msgid="4655101984031246476">"Wachtwoord gebruiken?"</string>
+ <string name="dialog_dismiss_button" msgid="989567669882005067">"Sluiten"</string>
+ <string name="dialog_continue_button" msgid="8630290044077052145">"Doorgaan"</string>
+ <string name="dialog_sign_in_options_button" msgid="448002958902615054">"Inlogopties"</string>
+ <string name="sign_in_options_title" msgid="6720572645638986680">"Inlogopties"</string>
+ <string name="provider_list_title" msgid="6803918216129492212">"Logins beheren"</string>
+ <string name="choose_sign_in_title" msgid="3616025924746872202">"Een login kiezen"</string>
+ <string name="choose_passkey_title" msgid="8459270617632817465">"Toegangssleutel kiezen"</string>
+ <string name="choose_password_title" msgid="7610721820858017214">"Wachtwoord kiezen"</string>
+ <string name="sign_in_on_phone_button" msgid="7618621977586522403">"Inloggen op telefoon"</string>
+ <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="1733094937495140605">"Geen inloggegevens"</string>
+ <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="4320941096211904568">"Tik om te ontgrendelen"</string>
+</resources>
diff --git a/packages/CredentialManager/wear/res/values-pt-rPT/strings.xml b/packages/CredentialManager/wear/res/values-pt-rPT/strings.xml
new file mode 100644
index 000000000000..acec24c31a41
--- /dev/null
+++ b/packages/CredentialManager/wear/res/values-pt-rPT/strings.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="7384524142163511792">"Gestor de credenciais"</string>
+ <string name="use_passkey_title" msgid="716598039340757817">"Usar a chave de acesso?"</string>
+ <string name="use_password_title" msgid="4655101984031246476">"Usar a palavra-passe?"</string>
+ <string name="dialog_dismiss_button" msgid="989567669882005067">"Ignorar"</string>
+ <string name="dialog_continue_button" msgid="8630290044077052145">"Continuar"</string>
+ <string name="dialog_sign_in_options_button" msgid="448002958902615054">"Opções de início de sessão"</string>
+ <string name="sign_in_options_title" msgid="6720572645638986680">"Opções de início de sessão"</string>
+ <string name="provider_list_title" msgid="6803918216129492212">"Faça a gestão dos inícios de sessão"</string>
+ <string name="choose_sign_in_title" msgid="3616025924746872202">"Escolha um início de sessão"</string>
+ <string name="choose_passkey_title" msgid="8459270617632817465">"Escolha a chave de acesso"</string>
+ <string name="choose_password_title" msgid="7610721820858017214">"Escolha a palavra-passe"</string>
+ <string name="sign_in_on_phone_button" msgid="7618621977586522403">"Iniciar sessão no telemóvel"</string>
+ <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="1733094937495140605">"Sem informações de início de sessão"</string>
+ <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="4320941096211904568">"Tocar para desbloquear"</string>
+</resources>
diff --git a/packages/CredentialManager/wear/res/values-sl/strings.xml b/packages/CredentialManager/wear/res/values-sl/strings.xml
new file mode 100644
index 000000000000..b76165edb907
--- /dev/null
+++ b/packages/CredentialManager/wear/res/values-sl/strings.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="7384524142163511792">"Upravitelj poverilnic"</string>
+ <string name="use_passkey_title" msgid="716598039340757817">"Želite uporabiti ključ za dostop?"</string>
+ <string name="use_password_title" msgid="4655101984031246476">"Želite uporabiti geslo?"</string>
+ <string name="dialog_dismiss_button" msgid="989567669882005067">"Opusti"</string>
+ <string name="dialog_continue_button" msgid="8630290044077052145">"Naprej"</string>
+ <string name="dialog_sign_in_options_button" msgid="448002958902615054">"Možnosti prijave"</string>
+ <string name="sign_in_options_title" msgid="6720572645638986680">"Možnosti prijave"</string>
+ <string name="provider_list_title" msgid="6803918216129492212">"Upravljanje podatkov za prijavo"</string>
+ <string name="choose_sign_in_title" msgid="3616025924746872202">"Izbira prijave"</string>
+ <string name="choose_passkey_title" msgid="8459270617632817465">"Izbira ključa za dostop"</string>
+ <string name="choose_password_title" msgid="7610721820858017214">"Izbira gesla"</string>
+ <string name="sign_in_on_phone_button" msgid="7618621977586522403">"Prijava v telefonu"</string>
+ <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="1733094937495140605">"Ni nobenih podatkov za prijavo"</string>
+ <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="4320941096211904568">"Dotaknite se, da odklenete"</string>
+</resources>
diff --git a/packages/CredentialManager/wear/res/values-sw/strings.xml b/packages/CredentialManager/wear/res/values-sw/strings.xml
new file mode 100644
index 000000000000..509c404c7926
--- /dev/null
+++ b/packages/CredentialManager/wear/res/values-sw/strings.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="7384524142163511792">"Kidhibiti cha Vitambulisho"</string>
+ <string name="use_passkey_title" msgid="716598039340757817">"Ungependa kutumia ufunguo wa siri?"</string>
+ <string name="use_password_title" msgid="4655101984031246476">"Ungependa kutumia nenosiri?"</string>
+ <string name="dialog_dismiss_button" msgid="989567669882005067">"Ondoa"</string>
+ <string name="dialog_continue_button" msgid="8630290044077052145">"Endelea"</string>
+ <string name="dialog_sign_in_options_button" msgid="448002958902615054">"Chaguo za Kuingia katika Akaunti"</string>
+ <string name="sign_in_options_title" msgid="6720572645638986680">"Chaguo za Kuingia katika Akaunti"</string>
+ <string name="provider_list_title" msgid="6803918216129492212">"Dhibiti michakato ya kuingia katika akaunti"</string>
+ <string name="choose_sign_in_title" msgid="3616025924746872202">"Chagua mbinu ya kuingia katika akaunti"</string>
+ <string name="choose_passkey_title" msgid="8459270617632817465">"Chagua ufunguo wa siri"</string>
+ <string name="choose_password_title" msgid="7610721820858017214">"Chagua nenosiri"</string>
+ <string name="sign_in_on_phone_button" msgid="7618621977586522403">"Ingia katika akaunti kwenye simu"</string>
+ <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="1733094937495140605">"Hakuna maelezo ya kuingia katika akaunti"</string>
+ <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="4320941096211904568">"Gusa ili ufungue"</string>
+</resources>
diff --git a/packages/CredentialManager/wear/res/values-ta/strings.xml b/packages/CredentialManager/wear/res/values-ta/strings.xml
new file mode 100644
index 000000000000..9f88c81b45c0
--- /dev/null
+++ b/packages/CredentialManager/wear/res/values-ta/strings.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="7384524142163511792">"அனுமதிச் சான்று நிர்வாகி"</string>
+ <string name="use_passkey_title" msgid="716598039340757817">"கடவுச்சாவியைப் பயன்படுத்தவா?"</string>
+ <string name="use_password_title" msgid="4655101984031246476">"கடவுச்சொல்லைப் பயன்படுத்தவா?"</string>
+ <string name="dialog_dismiss_button" msgid="989567669882005067">"மூடு"</string>
+ <string name="dialog_continue_button" msgid="8630290044077052145">"தொடர்க"</string>
+ <string name="dialog_sign_in_options_button" msgid="448002958902615054">"உள்நுழைவு விருப்பங்கள்"</string>
+ <string name="sign_in_options_title" msgid="6720572645638986680">"உள்நுழைவு விருப்பங்கள்"</string>
+ <string name="provider_list_title" msgid="6803918216129492212">"உள்நுழைவுகளை நிர்வகித்தல்"</string>
+ <string name="choose_sign_in_title" msgid="3616025924746872202">"உள்நுழைவைத் தேர்வுசெய்தல்"</string>
+ <string name="choose_passkey_title" msgid="8459270617632817465">"கடவுச்சாவியைத் தேர்வுசெய்தல்"</string>
+ <string name="choose_password_title" msgid="7610721820858017214">"கடவுச்சொல்லைத் தேர்வுசெய்தல்"</string>
+ <string name="sign_in_on_phone_button" msgid="7618621977586522403">"மொபைலில் உள்நுழைக"</string>
+ <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="1733094937495140605">"உள்நுழைவுத் தகவல் இல்லை"</string>
+ <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="4320941096211904568">"அன்லாக் செய்ய தட்டவும்"</string>
+</resources>
diff --git a/packages/CredentialManager/wear/res/values-te/strings.xml b/packages/CredentialManager/wear/res/values-te/strings.xml
new file mode 100644
index 000000000000..086b109b1933
--- /dev/null
+++ b/packages/CredentialManager/wear/res/values-te/strings.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="7384524142163511792">"సైన్-ఇన్ మేనేజర్"</string>
+ <string name="use_passkey_title" msgid="716598039340757817">"పాస్-కీని ఉపయోగిస్తారా?"</string>
+ <string name="use_password_title" msgid="4655101984031246476">"పాస్‌వర్డ్‌ను ఉపయోగిస్తారా?"</string>
+ <string name="dialog_dismiss_button" msgid="989567669882005067">"విస్మరించండి"</string>
+ <string name="dialog_continue_button" msgid="8630290044077052145">"కొనసాగించండి"</string>
+ <string name="dialog_sign_in_options_button" msgid="448002958902615054">"సైన్ ఇన్ ఆప్షన్‌లు"</string>
+ <string name="sign_in_options_title" msgid="6720572645638986680">"సైన్ ఇన్ ఆప్షన్‌లు"</string>
+ <string name="provider_list_title" msgid="6803918216129492212">"సైన్‌ ఇన్‌లను మేనేజ్ చేయండి"</string>
+ <string name="choose_sign_in_title" msgid="3616025924746872202">"సైన్ ఇన్‌ను ఎంచుకోండి"</string>
+ <string name="choose_passkey_title" msgid="8459270617632817465">"పాస్-కీని ఎంచుకోండి"</string>
+ <string name="choose_password_title" msgid="7610721820858017214">"పాస్‌వర్డ్‌ను ఎంచుకోండి"</string>
+ <string name="sign_in_on_phone_button" msgid="7618621977586522403">"ఫోన్‌లో సైన్ ఇన్ చేయండి"</string>
+ <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="1733094937495140605">"సైన్ ఇన్ సమాచారం ఏదీ లేదు"</string>
+ <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="4320941096211904568">"అన్‌లాక్ చేయడానికి ట్యాప్ చేయండి"</string>
+</resources>
diff --git a/packages/CredentialManager/wear/res/values-th/strings.xml b/packages/CredentialManager/wear/res/values-th/strings.xml
new file mode 100644
index 000000000000..5d4f7998378e
--- /dev/null
+++ b/packages/CredentialManager/wear/res/values-th/strings.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="7384524142163511792">"Credential Manager"</string>
+ <string name="use_passkey_title" msgid="716598039340757817">"ใช้พาสคีย์ไหม"</string>
+ <string name="use_password_title" msgid="4655101984031246476">"ใช้รหัสผ่านไหม"</string>
+ <string name="dialog_dismiss_button" msgid="989567669882005067">"ปิด"</string>
+ <string name="dialog_continue_button" msgid="8630290044077052145">"ต่อไป"</string>
+ <string name="dialog_sign_in_options_button" msgid="448002958902615054">"ตัวเลือกการลงชื่อเข้าใช้"</string>
+ <string name="sign_in_options_title" msgid="6720572645638986680">"ตัวเลือกการลงชื่อเข้าใช้"</string>
+ <string name="provider_list_title" msgid="6803918216129492212">"จัดการการลงชื่อเข้าใช้"</string>
+ <string name="choose_sign_in_title" msgid="3616025924746872202">"เลือกการลงชื่อเข้าใช้"</string>
+ <string name="choose_passkey_title" msgid="8459270617632817465">"เลือกพาสคีย์"</string>
+ <string name="choose_password_title" msgid="7610721820858017214">"เลือกรหัสผ่าน"</string>
+ <string name="sign_in_on_phone_button" msgid="7618621977586522403">"ลงชื่อเข้าใช้บนโทรศัพท์"</string>
+ <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="1733094937495140605">"ไม่มีข้อมูลการลงชื่อเข้าใช้"</string>
+ <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="4320941096211904568">"แตะเพื่อปลดล็อก"</string>
+</resources>
diff --git a/packages/CredentialManager/wear/res/values-tl/strings.xml b/packages/CredentialManager/wear/res/values-tl/strings.xml
new file mode 100644
index 000000000000..bd3e67238882
--- /dev/null
+++ b/packages/CredentialManager/wear/res/values-tl/strings.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="7384524142163511792">"Credential Manager"</string>
+ <string name="use_passkey_title" msgid="716598039340757817">"Gamitin ang passkey?"</string>
+ <string name="use_password_title" msgid="4655101984031246476">"Gamitin ang password?"</string>
+ <string name="dialog_dismiss_button" msgid="989567669882005067">"I-dismiss"</string>
+ <string name="dialog_continue_button" msgid="8630290044077052145">"Magpatuloy"</string>
+ <string name="dialog_sign_in_options_button" msgid="448002958902615054">"Mga Opsyon sa Pag-sign in"</string>
+ <string name="sign_in_options_title" msgid="6720572645638986680">"Mga Opsyon sa Pag-sign in"</string>
+ <string name="provider_list_title" msgid="6803918216129492212">"Pamahalaan ang mga pag-sign in"</string>
+ <string name="choose_sign_in_title" msgid="3616025924746872202">"Pumili ng pag-sign in"</string>
+ <string name="choose_passkey_title" msgid="8459270617632817465">"Pumili ng passkey"</string>
+ <string name="choose_password_title" msgid="7610721820858017214">"Pumili ng password"</string>
+ <string name="sign_in_on_phone_button" msgid="7618621977586522403">"Mag-sign in sa telepono"</string>
+ <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="1733094937495140605">"Walang impormasyon sa pag-sign in"</string>
+ <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="4320941096211904568">"I-tap para i-unlock"</string>
+</resources>
diff --git a/packages/CredentialManager/wear/res/values-ur/strings.xml b/packages/CredentialManager/wear/res/values-ur/strings.xml
new file mode 100644
index 000000000000..60bf163a1a5f
--- /dev/null
+++ b/packages/CredentialManager/wear/res/values-ur/strings.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="7384524142163511792">"اسناد مینیجر"</string>
+ <string name="use_passkey_title" msgid="716598039340757817">"پاس کی کا استعمال کریں؟"</string>
+ <string name="use_password_title" msgid="4655101984031246476">"پاس ورڈ کا استعمال کریں؟"</string>
+ <string name="dialog_dismiss_button" msgid="989567669882005067">"برخاست کریں"</string>
+ <string name="dialog_continue_button" msgid="8630290044077052145">"جاری رکھیں"</string>
+ <string name="dialog_sign_in_options_button" msgid="448002958902615054">"سائن ان کے اختیارات"</string>
+ <string name="sign_in_options_title" msgid="6720572645638986680">"سائن ان کے اختیارات"</string>
+ <string name="provider_list_title" msgid="6803918216129492212">"سائن انز کا نظم کریں"</string>
+ <string name="choose_sign_in_title" msgid="3616025924746872202">"سائن ان کا انتخاب کریں"</string>
+ <string name="choose_passkey_title" msgid="8459270617632817465">"پاس کی کا انتخاب کریں"</string>
+ <string name="choose_password_title" msgid="7610721820858017214">"پاس ورڈ منتخب کریں"</string>
+ <string name="sign_in_on_phone_button" msgid="7618621977586522403">"فون پر سائن ان کریں"</string>
+ <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="1733094937495140605">"سائن ان کی کوئی معلومات نہیں"</string>
+ <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="4320941096211904568">"غیر مقفل کرنے کیلئے تھپتھپائیں"</string>
+</resources>
diff --git a/packages/CredentialManager/wear/res/values-uz/strings.xml b/packages/CredentialManager/wear/res/values-uz/strings.xml
new file mode 100644
index 000000000000..3b630c792032
--- /dev/null
+++ b/packages/CredentialManager/wear/res/values-uz/strings.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="7384524142163511792">"Hisob maʼlumotlari boshqaruvi"</string>
+ <string name="use_passkey_title" msgid="716598039340757817">"Kirish kaliti ishlatilsinmi?"</string>
+ <string name="use_password_title" msgid="4655101984031246476">"Parol ishlatilsinmi?"</string>
+ <string name="dialog_dismiss_button" msgid="989567669882005067">"Yopish"</string>
+ <string name="dialog_continue_button" msgid="8630290044077052145">"Davom etish"</string>
+ <string name="dialog_sign_in_options_button" msgid="448002958902615054">"Kirish parametrlari"</string>
+ <string name="sign_in_options_title" msgid="6720572645638986680">"Kirish parametrlari"</string>
+ <string name="provider_list_title" msgid="6803918216129492212">"Kirishni boshqarish"</string>
+ <string name="choose_sign_in_title" msgid="3616025924746872202">"Kirish axborotini tanlash"</string>
+ <string name="choose_passkey_title" msgid="8459270617632817465">"Kalit tanlash"</string>
+ <string name="choose_password_title" msgid="7610721820858017214">"Parol tanlash"</string>
+ <string name="sign_in_on_phone_button" msgid="7618621977586522403">"Telefonda hisobga kirish"</string>
+ <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="1733094937495140605">"Kirish axboroti topilmadi"</string>
+ <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="4320941096211904568">"Qulfni ochish uchun bosing"</string>
+</resources>
diff --git a/packages/CredentialManager/wear/res/values-vi/strings.xml b/packages/CredentialManager/wear/res/values-vi/strings.xml
new file mode 100644
index 000000000000..476d9bcaf9c8
--- /dev/null
+++ b/packages/CredentialManager/wear/res/values-vi/strings.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="7384524142163511792">"Trình quản lý thông tin xác thực"</string>
+ <string name="use_passkey_title" msgid="716598039340757817">"Dùng khoá truy cập?"</string>
+ <string name="use_password_title" msgid="4655101984031246476">"Dùng mật khẩu?"</string>
+ <string name="dialog_dismiss_button" msgid="989567669882005067">"Đóng"</string>
+ <string name="dialog_continue_button" msgid="8630290044077052145">"Tiếp tục"</string>
+ <string name="dialog_sign_in_options_button" msgid="448002958902615054">"Phương thức đăng nhập"</string>
+ <string name="sign_in_options_title" msgid="6720572645638986680">"Phương thức đăng nhập"</string>
+ <string name="provider_list_title" msgid="6803918216129492212">"Quản lý thông tin đăng nhập"</string>
+ <string name="choose_sign_in_title" msgid="3616025924746872202">"Chọn một phương thức đăng nhập"</string>
+ <string name="choose_passkey_title" msgid="8459270617632817465">"Chọn khoá truy cập"</string>
+ <string name="choose_password_title" msgid="7610721820858017214">"Chọn mật khẩu"</string>
+ <string name="sign_in_on_phone_button" msgid="7618621977586522403">"Đăng nhập trên điện thoại"</string>
+ <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="1733094937495140605">"Không có thông tin đăng nhập"</string>
+ <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="4320941096211904568">"Nhấn để mở khoá"</string>
+</resources>
diff --git a/packages/CredentialManager/wear/res/values-zh-rHK/strings.xml b/packages/CredentialManager/wear/res/values-zh-rHK/strings.xml
new file mode 100644
index 000000000000..4e0484918baf
--- /dev/null
+++ b/packages/CredentialManager/wear/res/values-zh-rHK/strings.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="7384524142163511792">"憑證管理工具"</string>
+ <string name="use_passkey_title" msgid="716598039340757817">"要使用密鑰嗎?"</string>
+ <string name="use_password_title" msgid="4655101984031246476">"要使用密碼嗎?"</string>
+ <string name="dialog_dismiss_button" msgid="989567669882005067">"關閉"</string>
+ <string name="dialog_continue_button" msgid="8630290044077052145">"繼續"</string>
+ <string name="dialog_sign_in_options_button" msgid="448002958902615054">"登入方式"</string>
+ <string name="sign_in_options_title" msgid="6720572645638986680">"登入方式"</string>
+ <string name="provider_list_title" msgid="6803918216129492212">"管理登入方式"</string>
+ <string name="choose_sign_in_title" msgid="3616025924746872202">"選擇登入憑證"</string>
+ <string name="choose_passkey_title" msgid="8459270617632817465">"選擇密鑰"</string>
+ <string name="choose_password_title" msgid="7610721820858017214">"選擇密碼"</string>
+ <string name="sign_in_on_phone_button" msgid="7618621977586522403">"在手機上登入"</string>
+ <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="1733094937495140605">"沒有登入資料"</string>
+ <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="4320941096211904568">"輕按即可解鎖"</string>
+</resources>
diff --git a/packages/PackageInstaller/res/values-fr-rCA/strings.xml b/packages/PackageInstaller/res/values-fr-rCA/strings.xml
index 60075e6703fb..2e423396fbd8 100644
--- a/packages/PackageInstaller/res/values-fr-rCA/strings.xml
+++ b/packages/PackageInstaller/res/values-fr-rCA/strings.xml
@@ -23,55 +23,55 @@
<string name="cancel" msgid="1018267193425558088">"Annuler"</string>
<string name="installing" msgid="4921993079741206516">"Installation en cours…"</string>
<string name="installing_app" msgid="1165095864863849422">"Installation de <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> en cours…"</string>
- <string name="install_done" msgid="5987363587661783896">"Application installée."</string>
- <string name="install_confirm_question" msgid="7663733664476363311">"Voulez-vous installer cette application?"</string>
- <string name="install_confirm_question_update" msgid="3348888852318388584">"Voulez-vous mettre à jour cette application?"</string>
- <string name="install_confirm_question_update_owner_reminder" product="tablet" msgid="7994800761970572198">"&lt;p&gt;Mettre à jour cette application à partir de &lt;b&gt;<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>&lt;/b&gt;?&lt;/p&gt;&lt;p&gt;Cette application reçoit normalement des mises à jour de &lt;b&gt;<xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>&lt;/b&gt;. En effectuant une mise à jour à partir d\'une source différente, vous pourriez recevoir des mises à jour futures à partir de n\'importe quelle source sur votre tablette. Le fonctionnement de l\'application peut en être modifié.&lt;/p&gt;"</string>
- <string name="install_confirm_question_update_owner_reminder" product="tv" msgid="2435174886412089791">"&lt;p&gt;Mettre à jour cette application à partir de &lt;b&gt;<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>&lt;/b&gt;?&lt;/p&gt;&lt;p&gt;Cette application reçoit normalement des mises à jour de &lt;b&gt;<xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>&lt;/b&gt;. En effectuant une mise à jour à partir d\'une source différente, vous pourriez recevoir des mises à jour futures à partir de n\'importe quelle source sur votre téléviseur. Le fonctionnement de l\'application peut en être modifié.&lt;/p&gt;"</string>
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="7155138616126795839">"&lt;p&gt;Mettre à jour cette application à partir de &lt;b&gt;<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>&lt;/b&gt;?&lt;/p&gt;&lt;p&gt;Cette application reçoit normalement des mises à jour de &lt;b&gt;<xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>&lt;/b&gt;. En effectuant une mise à jour à partir d\'une source différente, vous pourriez recevoir des mises à jour futures à partir de n\'importe quelle source sur votre téléphone. Le fonctionnement de l\'application peut en être modifié.&lt;/p&gt;"</string>
- <string name="install_failed" msgid="5777824004474125469">"Application non installée."</string>
+ <string name="install_done" msgid="5987363587661783896">"Appli installée."</string>
+ <string name="install_confirm_question" msgid="7663733664476363311">"Voulez-vous installer cette appli?"</string>
+ <string name="install_confirm_question_update" msgid="3348888852318388584">"Voulez-vous mettre à jour cette appli?"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tablet" msgid="7994800761970572198">"&lt;p&gt;Mettre à jour cette appli à partir de &lt;b&gt;<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>&lt;/b&gt;?&lt;/p&gt;&lt;p&gt;Cette appli reçoit normalement des mises à jour de &lt;b&gt;<xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>&lt;/b&gt;. En effectuant une mise à jour à partir d\'une source différente, vous pourriez recevoir des mises à jour futures à partir de n\'importe quelle source sur votre tablette. Le fonctionnement de l\'appli peut en être modifié.&lt;/p&gt;"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tv" msgid="2435174886412089791">"&lt;p&gt;Mettre à jour cette appli à partir de &lt;b&gt;<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>&lt;/b&gt;?&lt;/p&gt;&lt;p&gt;Cette appli reçoit normalement des mises à jour de &lt;b&gt;<xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>&lt;/b&gt;. En effectuant une mise à jour à partir d\'une source différente, vous pourriez recevoir des mises à jour futures à partir de n\'importe quelle source sur votre téléviseur. Le fonctionnement de l\'appli peut en être modifié.&lt;/p&gt;"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="7155138616126795839">"&lt;p&gt;Mettre à jour cette appli à partir de &lt;b&gt;<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>&lt;/b&gt;?&lt;/p&gt;&lt;p&gt;Cette appli reçoit normalement des mises à jour de &lt;b&gt;<xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>&lt;/b&gt;. En effectuant une mise à jour à partir d\'une source différente, vous pourriez recevoir des mises à jour futures à partir de n\'importe quelle source sur votre téléphone. Le fonctionnement de l\'appli peut en être modifié.&lt;/p&gt;"</string>
+ <string name="install_failed" msgid="5777824004474125469">"Appli non installée."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"L\'installation du paquet a été bloquée."</string>
- <string name="install_failed_conflict" msgid="3493184212162521426">"L\'application n\'a pas été installée, car le paquet entre en conflit avec un paquet existant."</string>
- <string name="install_failed_incompatible" product="tablet" msgid="6019021440094927928">"L\'application n\'a pas été installée, car elle n\'est pas compatible avec votre tablette."</string>
- <string name="install_failed_incompatible" product="tv" msgid="2890001324362291683">"Cette application n\'est pas compatible avec votre téléviseur."</string>
- <string name="install_failed_incompatible" product="default" msgid="7254630419511645826">"L\'application n\'a pas été installée, car elle n\'est pas compatible avec votre téléphone."</string>
- <string name="install_failed_invalid_apk" msgid="8581007676422623930">"L\'application n\'a pas été installée, car elle ne semble pas être valide."</string>
+ <string name="install_failed_conflict" msgid="3493184212162521426">"L\'appli n\'a pas été installée, car le paquet entre en conflit avec un paquet existant."</string>
+ <string name="install_failed_incompatible" product="tablet" msgid="6019021440094927928">"L\'appli n\'a pas été installée, car elle n\'est pas compatible avec votre tablette."</string>
+ <string name="install_failed_incompatible" product="tv" msgid="2890001324362291683">"Cette appli n\'est pas compatible avec votre téléviseur."</string>
+ <string name="install_failed_incompatible" product="default" msgid="7254630419511645826">"L\'appli n\'a pas été installée, car elle n\'est pas compatible avec votre téléphone."</string>
+ <string name="install_failed_invalid_apk" msgid="8581007676422623930">"L\'appli n\'a pas été installée, car elle ne semble pas être valide."</string>
<string name="install_failed_msg" product="tablet" msgid="6298387264270562442">"Impossible d\'installer <xliff:g id="APP_NAME">%1$s</xliff:g> sur votre tablette."</string>
<string name="install_failed_msg" product="tv" msgid="1920009940048975221">"<xliff:g id="APP_NAME">%1$s</xliff:g> n\'a pas pu être installée sur votre téléviseur."</string>
<string name="install_failed_msg" product="default" msgid="6484461562647915707">"Impossible d\'installer <xliff:g id="APP_NAME">%1$s</xliff:g> sur votre téléphone."</string>
<string name="launch" msgid="3952550563999890101">"Ouvrir"</string>
- <string name="unknown_apps_admin_dlg_text" msgid="4456572224020176095">"Votre administrateur n\'autorise pas l\'installation d\'applications obtenues à partir de sources inconnues"</string>
- <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Cet utilisateur ne peut pas installer d\'applications inconnues"</string>
- <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Cet utilisateur n\'est pas autorisé à installer des applications"</string>
+ <string name="unknown_apps_admin_dlg_text" msgid="4456572224020176095">"Votre administrateur n\'autorise pas l\'installation d\'applis obtenues à partir de sources inconnues"</string>
+ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Cet utilisateur ne peut pas installer d\'applis inconnues"</string>
+ <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Cet utilisateur n\'est pas autorisé à installer des applis"</string>
<string name="ok" msgid="7871959885003339302">"OK"</string>
<string name="archive" msgid="4447791830199354721">"Archiver"</string>
<string name="update_anyway" msgid="8792432341346261969">"Mettre à jour malgré tout"</string>
<string name="manage_applications" msgid="5400164782453975580">"Gérer les applis"</string>
<string name="out_of_space_dlg_title" msgid="4156690013884649502">"Espace insuffisant"</string>
<string name="out_of_space_dlg_text" msgid="8727714096031856231">"Impossible d\'installer <xliff:g id="APP_NAME">%1$s</xliff:g>. Veuillez libérer de l\'espace, puis réessayer."</string>
- <string name="app_not_found_dlg_title" msgid="5107924008597470285">"Application non trouvée"</string>
- <string name="app_not_found_dlg_text" msgid="5219983779377811611">"L\'application ne figure pas dans la liste des applications installées."</string>
+ <string name="app_not_found_dlg_title" msgid="5107924008597470285">"Appli non trouvée"</string>
+ <string name="app_not_found_dlg_text" msgid="5219983779377811611">"L\'appli ne figure pas dans la liste des applis installées."</string>
<string name="user_is_not_allowed_dlg_title" msgid="6915293433252210232">"Non autorisée"</string>
<string name="user_is_not_allowed_dlg_text" msgid="3468447791330611681">"L\'utilisateur actuel n\'est pas autorisé à effectuer cette désinstallation."</string>
<string name="generic_error_dlg_title" msgid="5863195085927067752">"Erreur"</string>
- <string name="generic_error_dlg_text" msgid="5287861443265795232">"L\'application n\'a pas pu être désinstallée."</string>
- <string name="uninstall_application_title" msgid="4045420072401428123">"Désinstaller l\'application"</string>
+ <string name="generic_error_dlg_text" msgid="5287861443265795232">"L\'appli n\'a pas pu être désinstallée."</string>
+ <string name="uninstall_application_title" msgid="4045420072401428123">"Désinstaller l\'appli"</string>
<string name="uninstall_update_title" msgid="824411791011583031">"Désinstaller mise à jour"</string>
- <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> fait partie de l\'application suivante :"</string>
- <string name="uninstall_application_text" msgid="3816830743706143980">"Voulez-vous désinstaller cette application?"</string>
+ <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> fait partie de l\'appli suivante :"</string>
+ <string name="uninstall_application_text" msgid="3816830743706143980">"Voulez-vous désinstaller cette appli?"</string>
<string name="archive_application_text" msgid="8482325710714386348">"Vos données personnelles seront enregistrées"</string>
- <string name="archive_application_text_all_users" msgid="3151229641681672580">"Archiver cette application pour tous les utilisateurs? Vos données personnelles seront enregistrées"</string>
- <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"Archiver cette application sur votre profil professionnel? Vos données personnelles seront enregistrées"</string>
- <string name="archive_application_text_user" msgid="2586558895535581451">"Archiver cette application pour <xliff:g id="USERNAME">%1$s</xliff:g>? Vos données personnelles seront enregistrées"</string>
- <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"Voulez-vous archiver cette application de votre Espace privé? Vos données personnelles seront enregistrées"</string>
- <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Voulez-vous désinstaller cette application pour "<b>"tous"</b>" les utilisateurs? L\'application et ses données seront supprimées pour "<b>"tous"</b>" les utilisateurs de l\'appareil."</string>
- <string name="uninstall_application_text_user" msgid="498072714173920526">"Voulez-vous désinstaller cette application pour l\'utilisateur <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
- <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Voulez-vous désinstaller cette application de votre profil professionnel?"</string>
- <string name="uninstall_update_text" msgid="863648314632448705">"Remplacer cette application par la version d\'usine? Toutes les données seront supprimées."</string>
- <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Remplacer cette application par la version d\'usine? Toutes les données seront supprimées. Cela touchera tous les utilisateurs de cet appareil, y compris ceux qui utilisent un profil professionnel."</string>
- <string name="uninstall_keep_data" msgid="7002379587465487550">"Garder <xliff:g id="SIZE">%1$s</xliff:g> de données d\'application."</string>
- <string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Voulez-vous supprimer cette application?"</string>
- <string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Voulez-vous désinstaller cette application? Le clone de <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> sera aussi supprimé."</string>
+ <string name="archive_application_text_all_users" msgid="3151229641681672580">"Archiver cette appli pour tous les utilisateurs? Vos données personnelles seront enregistrées"</string>
+ <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"Archiver cette appli sur votre profil professionnel? Vos données personnelles seront enregistrées"</string>
+ <string name="archive_application_text_user" msgid="2586558895535581451">"Archiver cette appli pour <xliff:g id="USERNAME">%1$s</xliff:g>? Vos données personnelles seront enregistrées"</string>
+ <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"Voulez-vous archiver cette appli de votre Espace privé? Vos données personnelles seront enregistrées"</string>
+ <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Voulez-vous désinstaller cette appli pour "<b>"tous"</b>" les utilisateurs? L\'appli et ses données seront supprimées pour "<b>"tous"</b>" les utilisateurs de l\'appareil."</string>
+ <string name="uninstall_application_text_user" msgid="498072714173920526">"Voulez-vous désinstaller cette appli pour l\'utilisateur <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Voulez-vous désinstaller cette appli de votre profil professionnel?"</string>
+ <string name="uninstall_update_text" msgid="863648314632448705">"Remplacer cette appli par la version d\'usine? Toutes les données seront supprimées."</string>
+ <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Remplacer cette appli par la version d\'usine? Toutes les données seront supprimées. Cela touchera tous les utilisateurs de cet appareil, y compris ceux qui utilisent un profil professionnel."</string>
+ <string name="uninstall_keep_data" msgid="7002379587465487550">"Garder <xliff:g id="SIZE">%1$s</xliff:g> de données d\'appli."</string>
+ <string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Voulez-vous supprimer cette appli?"</string>
+ <string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Voulez-vous désinstaller cette appli? Le clone de <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> sera aussi supprimé."</string>
<string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"Voulez-vous désinstaller cette appli de votre espace privé?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Désinstallations en cours…"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Désinstallations échouées"</string>
@@ -83,47 +83,47 @@
<string name="uninstall_failed" msgid="1847750968168364332">"Échec de la désinstallation."</string>
<string name="uninstall_failed_app" msgid="5506028705017601412">"La désinstallation de <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> n\'a pas réussi."</string>
<string name="uninstalling_cloned_app" msgid="1826380164974984870">"Suppression du clone <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>…"</string>
- <string name="uninstall_failed_device_policy_manager" msgid="785293813665540305">"Impossible de désinstaller une application d\'administration de l\'appareil active"</string>
- <string name="uninstall_failed_device_policy_manager_of_user" msgid="4813104025494168064">"Impossible de désinstaller une application d\'administration de l\'appareil active pour <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
- <string name="uninstall_all_blocked_profile_owner" msgid="2009393666026751501">"Cette application est nécessaire pour certains utilisateurs ou profils, et elle a été désinstallée pour d\'autres"</string>
- <string name="uninstall_blocked_profile_owner" msgid="6373897407002404848">"Cette application est nécessaire pour votre profil et ne peut pas être désinstallée."</string>
- <string name="uninstall_blocked_device_owner" msgid="6724602931761073901">"Imposs. de désinst. l\'application : elle est requise par l\'admin de l\'appareil."</string>
- <string name="manage_device_administrators" msgid="3092696419363842816">"Gérer les applications d\'administration d\'appareils"</string>
+ <string name="uninstall_failed_device_policy_manager" msgid="785293813665540305">"Impossible de désinstaller une appli d\'administration de l\'appareil active"</string>
+ <string name="uninstall_failed_device_policy_manager_of_user" msgid="4813104025494168064">"Impossible de désinstaller une appli d\'administration de l\'appareil active pour <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
+ <string name="uninstall_all_blocked_profile_owner" msgid="2009393666026751501">"Cette appli est nécessaire pour certains utilisateurs ou profils, et elle a été désinstallée pour d\'autres"</string>
+ <string name="uninstall_blocked_profile_owner" msgid="6373897407002404848">"Cette appli est nécessaire pour votre profil et ne peut pas être désinstallée."</string>
+ <string name="uninstall_blocked_device_owner" msgid="6724602931761073901">"Imposs. de désinst. l\'appli : elle est requise par l\'admin de l\'appareil."</string>
+ <string name="manage_device_administrators" msgid="3092696419363842816">"Gérer les applis d\'administration d\'appareils"</string>
<string name="manage_users" msgid="1243995386982560813">"Gérer les utilisateurs"</string>
<string name="uninstall_failed_msg" msgid="2176744834786696012">"Impossible de désinstaller <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="Parse_error_dlg_text" msgid="1661404001063076789">"Un problème est survenu lors de l\'analyse du paquet."</string>
- <string name="message_staging" msgid="8032722385658438567">"Pré-production de l\'application en cours…"</string>
+ <string name="message_staging" msgid="8032722385658438567">"Pré-production de l\'appli en cours…"</string>
<string name="app_name_unknown" msgid="6881210203354323926">"Inconnue"</string>
- <string name="untrusted_external_source_warning" product="tablet" msgid="7067510047443133095">"À des fins de sécurité, l\'installation d\'applications inconnues provenant de cette source n\'est pas autorisée sur cette tablette. Vous pouvez modifier cette option dans les paramètres."</string>
- <string name="untrusted_external_source_warning" product="tv" msgid="7057271609532508035">"À des fins de sécurité, l\'installation d\'applications inconnues provenant de cette source n\'est pas autorisée sur ce téléviseur. Vous pouvez modifier cette option dans les paramètres."</string>
- <string name="untrusted_external_source_warning" product="watch" msgid="7195163388090818636">"À des fins de sécurité, l\'installation d\'applications inconnues provenant de cette source n\'est pas autorisée sur cette montre. Vous pouvez modifier cette option dans les paramètres."</string>
- <string name="untrusted_external_source_warning" product="default" msgid="8444191224459138919">"À des fins de sécurité, l\'installation d\'applications inconnues provenant de cette source n\'est pas autorisée sur ce téléphone. Vous pouvez modifier cette option dans les paramètres."</string>
- <string name="anonymous_source_warning" product="default" msgid="2784902545920822500">"Votre téléphone et vos données personnelles sont plus vulnérables aux attaques provenant d\'applications inconnues. En installant cette application, vous acceptez d\'être le seul responsable de tout dommage causé à votre téléphone ou de toute perte de données pouvant découler de l\'utilisation de telles applications."</string>
- <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Votre tablette et vos données personnelles sont plus vulnérables aux attaques provenant d\'applications inconnues. En installant cette application, vous acceptez d\'être le seul responsable de tout dommage causé à votre tablette ou de toute perte de données pouvant découler de l\'utilisation de telles applications."</string>
- <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"Votre téléviseur et vos données personnelles sont plus vulnérables aux attaques d\'applications inconnues. En installant cette application, vous acceptez d\'être le seul responsable de tout dommage causé à votre téléviseur ou de toute perte de données pouvant découler de son utilisation."</string>
+ <string name="untrusted_external_source_warning" product="tablet" msgid="7067510047443133095">"À des fins de sécurité, l\'installation d\'applis inconnues provenant de cette source n\'est pas autorisée sur cette tablette. Vous pouvez modifier cette option dans les paramètres."</string>
+ <string name="untrusted_external_source_warning" product="tv" msgid="7057271609532508035">"À des fins de sécurité, l\'installation d\'applis inconnues provenant de cette source n\'est pas autorisée sur ce téléviseur. Vous pouvez modifier cette option dans les paramètres."</string>
+ <string name="untrusted_external_source_warning" product="watch" msgid="7195163388090818636">"À des fins de sécurité, l\'installation d\'applis inconnues provenant de cette source n\'est pas autorisée sur cette montre. Vous pouvez modifier cette option dans les paramètres."</string>
+ <string name="untrusted_external_source_warning" product="default" msgid="8444191224459138919">"À des fins de sécurité, l\'installation d\'applis inconnues provenant de cette source n\'est pas autorisée sur ce téléphone. Vous pouvez modifier cette option dans les paramètres."</string>
+ <string name="anonymous_source_warning" product="default" msgid="2784902545920822500">"Votre téléphone et vos données personnelles sont plus vulnérables aux attaques provenant d\'applis inconnues. En installant cette appli, vous acceptez d\'être le seul responsable de tout dommage causé à votre téléphone ou de toute perte de données pouvant découler de l\'utilisation de telles applis."</string>
+ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Votre tablette et vos données personnelles sont plus vulnérables aux attaques provenant d\'applis inconnues. En installant cette appli, vous acceptez d\'être le seul responsable de tout dommage causé à votre tablette ou de toute perte de données pouvant découler de l\'utilisation de telles applis."</string>
+ <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"Votre téléviseur et vos données personnelles sont plus vulnérables aux attaques d\'applis inconnues. En installant cette appli, vous acceptez d\'être le seul responsable de tout dommage causé à votre téléviseur ou de toute perte de données pouvant découler de son utilisation."</string>
<string name="cloned_app_label" msgid="7503612829833756160">"Clone de <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string>
<string name="archiving_app_label" msgid="1127085259724124725">"Archiver <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>?"</string>
<string name="anonymous_source_continue" msgid="4375745439457209366">"Continuer"</string>
<string name="external_sources_settings" msgid="4046964413071713807">"Paramètres"</string>
<string name="wear_app_channel" msgid="1960809674709107850">"Installer/désinstaller applis Google Wear"</string>
- <string name="app_installed_notification_channel_description" msgid="2695385797601574123">"Notification d\'application installée"</string>
+ <string name="app_installed_notification_channel_description" msgid="2695385797601574123">"Notification d\'appli installée"</string>
<string name="notification_installation_success_message" msgid="6450467996056038442">"Installation réussie"</string>
<string name="notification_installation_success_status" msgid="3172502643504323321">"Installation de « <xliff:g id="APPNAME">%1$s</xliff:g> » réussie"</string>
<string name="unarchive_application_title" msgid="7958278328280721421">"Restaurer <xliff:g id="APPNAME">%1$s</xliff:g> à partir de <xliff:g id="INSTALLERNAME">%2$s</xliff:g>?"</string>
- <string name="unarchive_body_text" msgid="8244155079861708964">"Le téléchargement de cette application commencera en arrière-plan"</string>
+ <string name="unarchive_body_text" msgid="8244155079861708964">"Le téléchargement de cette appli commencera en arrière-plan"</string>
<string name="restore" msgid="8460854736328970444">"Restaurer"</string>
<string name="unarchive_error_offline_title" msgid="4021785324565678605">"Vous êtes hors ligne"</string>
- <string name="unarchive_error_offline_body" msgid="2256042209364094099">"Pour restaurer cette application, vérifiez votre connexion Internet et réessayez."</string>
+ <string name="unarchive_error_offline_body" msgid="2256042209364094099">"Pour restaurer cette appli, vérifiez votre connexion Internet et réessayez."</string>
<string name="unarchive_error_generic_title" msgid="7123457671482449992">"Un problème est survenu"</string>
- <string name="unarchive_error_generic_body" msgid="4486803312463813079">"Un problème est survenu lors de la restauration de cette application"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"Un problème est survenu lors de la restauration de cette appli"</string>
<string name="unarchive_error_storage_title" msgid="5080723357273852630">"Espace de stockage insuffisant"</string>
- <string name="unarchive_error_storage_body" msgid="6879544407568780524">"Pour restaurer cette application, vous devez libérer de l\'espace de stockage sur cet appareil. Espace de stockage requis : <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"Pour restaurer cette appli, vous devez libérer de l\'espace de stockage sur cet appareil. Espace de stockage requis : <xliff:g id="BYTES">%1$s</xliff:g>"</string>
<string name="unarchive_action_required_title" msgid="4971245740162604619">"Action requise"</string>
- <string name="unarchive_action_required_body" msgid="1679431572983989231">"Suivez les étapes suivantes pour restaurer cette application"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"Suivez les étapes suivantes pour restaurer cette appli"</string>
<string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> est désactivé"</string>
- <string name="unarchive_error_installer_disabled_body" msgid="4820821285907011729">"Pour restaurer cette application, activez <xliff:g id="INSTALLERNAME">%1$s</xliff:g> dans les paramètres"</string>
+ <string name="unarchive_error_installer_disabled_body" msgid="4820821285907011729">"Pour restaurer cette appli, activez <xliff:g id="INSTALLERNAME">%1$s</xliff:g> dans les paramètres"</string>
<string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> est désinstallé"</string>
- <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"Pour restaurer cette application, vous devrez installer <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"Pour restaurer cette appli, vous devrez installer <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
<string name="unarchive_action_required_continue" msgid="5711202111224184257">"Continuer"</string>
<string name="unarchive_clear_storage_button" msgid="1549537154535608744">"Effacer le stockage"</string>
<string name="unarchive_settings_button" msgid="3504171760009177425">"Paramètres"</string>
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 c260426d47f5..88770d487a83 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/InstallRepository.kt
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/InstallRepository.kt
@@ -206,7 +206,7 @@ class InstallRepository(private val context: Context) {
return InstallAborted(ABORT_REASON_INTERNAL_ERROR)
}
- val restriction = getDevicePolicyRestrictions()
+ val restriction = getDevicePolicyRestrictions(isTrustedSource)
if (restriction != null) {
val adminSupportDetailsIntent =
devicePolicyManager!!.createAdminSupportIntent(restriction)
@@ -237,18 +237,25 @@ class InstallRepository(private val context: Context) {
intent: Intent,
callingUid: Int,
): Boolean {
- val isNotUnknownSource = intent.getBooleanExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, false)
- return (sourceInfo != null && sourceInfo.isPrivilegedApp
- && (isNotUnknownSource
- || isPermissionGranted(context, Manifest.permission.INSTALL_PACKAGES, callingUid)))
+ val isPrivilegedAndKnown = sourceInfo != null && sourceInfo.isPrivilegedApp &&
+ intent.getBooleanExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, false)
+ val isInstallPkgPermissionGranted =
+ isPermissionGranted(context, Manifest.permission.INSTALL_PACKAGES, callingUid)
+
+ return isPrivilegedAndKnown || isInstallPkgPermissionGranted
}
- private fun getDevicePolicyRestrictions(): String? {
- val restrictions = arrayOf(
- UserManager.DISALLOW_INSTALL_APPS,
- UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES,
- UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY
- )
+ private fun getDevicePolicyRestrictions(isTrustedSource: Boolean): String? {
+ val restrictions: Array<String> = if (isTrustedSource) {
+ arrayOf(UserManager.DISALLOW_INSTALL_APPS)
+ } else {
+ arrayOf(
+ UserManager.DISALLOW_INSTALL_APPS,
+ UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES,
+ UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY
+ )
+ }
+
for (restriction in restrictions) {
if (!userManager!!.hasUserRestrictionForUser(restriction, Process.myUserHandle())) {
continue
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/PackageUtil.kt b/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/PackageUtil.kt
index 85728528a25c..828a95fcbb01 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/PackageUtil.kt
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/PackageUtil.kt
@@ -130,8 +130,8 @@ object PackageUtil {
* @param context the [Context] object
* @param callingUid the UID of the caller of Pia
* @param isTrustedSource indicates whether install request is coming from a privileged app
- * that has passed EXTRA_NOT_UNKNOWN_SOURCE as `true` in the installation intent, or that has
- * the [INSTALL_PACKAGES][Manifest.permission.INSTALL_PACKAGES] permission granted.
+ * that has passed EXTRA_NOT_UNKNOWN_SOURCE as `true` in the installation intent, or an app that
+ * has the [INSTALL_PACKAGES][Manifest.permission.INSTALL_PACKAGES] permission granted.
*
* @return `true` if the package is either a system downloads provider, a document manager,
* a trusted source, or has declared the
diff --git a/packages/PrintSpooler/res/values-fr-rCA/strings.xml b/packages/PrintSpooler/res/values-fr-rCA/strings.xml
index 6ffad709b2f3..c2b82afa238a 100644
--- a/packages/PrintSpooler/res/values-fr-rCA/strings.xml
+++ b/packages/PrintSpooler/res/values-fr-rCA/strings.xml
@@ -33,7 +33,7 @@
<string name="pages_range_example" msgid="8558694453556945172">"p. ex. 1-5, 8, 11-13"</string>
<string name="print_preview" msgid="8010217796057763343">"Aperçu avant impression"</string>
<string name="install_for_print_preview" msgid="6366303997385509332">"Installer un lecteur PDF pour voir l\'aperçu"</string>
- <string name="printing_app_crashed" msgid="854477616686566398">"L\'application à l\'origine de l\'impression a planté"</string>
+ <string name="printing_app_crashed" msgid="854477616686566398">"L\'appli à l\'origine de l\'impression a planté"</string>
<string name="generating_print_job" msgid="3119608742651698916">"Génération tâche impression…"</string>
<string name="save_as_pdf" msgid="5718454119847596853">"Enregistrer au format PDF"</string>
<string name="all_printers" msgid="5018829726861876202">"Toutes les imprimantes…"</string>
diff --git a/packages/SettingsLib/AppPreference/res/values-fr-rCA/strings.xml b/packages/SettingsLib/AppPreference/res/values-fr-rCA/strings.xml
index 7be1e97f51e0..4771382de59b 100644
--- a/packages/SettingsLib/AppPreference/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/AppPreference/res/values-fr-rCA/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="install_type_instant" msgid="7217305006127216917">"Application instantanée"</string>
+ <string name="install_type_instant" msgid="7217305006127216917">"Appli instantanée"</string>
</resources>
diff --git a/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java b/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java
index bbf0315aa475..4387b6f061c3 100644
--- a/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java
+++ b/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java
@@ -16,6 +16,8 @@
package com.android.settingslib.widget;
+import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_YES;
+
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
@@ -122,6 +124,8 @@ public class IllustrationPreference extends Preference {
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
+ final FrameLayout illustrationFrame = (FrameLayout) holder.findViewById(
+ R.id.illustration_frame);
final ImageView backgroundView =
(ImageView) holder.findViewById(R.id.background_view);
final FrameLayout middleGroundLayout =
@@ -130,15 +134,15 @@ public class IllustrationPreference extends Preference {
(LottieAnimationView) holder.findViewById(R.id.lottie_view);
if (illustrationView != null && !TextUtils.isEmpty(mContentDescription)) {
illustrationView.setContentDescription(mContentDescription);
- illustrationView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
+ illustrationView.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
+ final View illustrationContainer = (View) illustrationFrame.getParent();
+ illustrationContainer.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
}
// To solve the problem of non-compliant illustrations, we set the frame height
// to 300dp and set the length of the short side of the screen to
// the width of the frame.
final int screenWidth = getContext().getResources().getDisplayMetrics().widthPixels;
final int screenHeight = getContext().getResources().getDisplayMetrics().heightPixels;
- final FrameLayout illustrationFrame = (FrameLayout) holder.findViewById(
- R.id.illustration_frame);
final LayoutParams lp = (LayoutParams) illustrationFrame.getLayoutParams();
lp.width = screenWidth < screenHeight ? screenWidth : screenHeight;
illustrationFrame.setLayoutParams(lp);
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/DebugActivity.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/DebugActivity.kt
index 14af5084d625..296579333115 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/DebugActivity.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/DebugActivity.kt
@@ -16,7 +16,6 @@
package com.android.settingslib.spa.debug
-import android.net.Uri
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
@@ -41,8 +40,6 @@ import com.android.settingslib.spa.framework.theme.SettingsTheme
import com.android.settingslib.spa.framework.util.SESSION_BROWSE
import com.android.settingslib.spa.framework.util.SESSION_SEARCH
import com.android.settingslib.spa.framework.util.createIntent
-import com.android.settingslib.spa.slice.fromEntry
-import com.android.settingslib.spa.slice.presenter.SliceDemo
import com.android.settingslib.spa.widget.preference.Preference
import com.android.settingslib.spa.widget.preference.PreferenceModel
import com.android.settingslib.spa.widget.scaffold.HomeScaffold
@@ -52,7 +49,6 @@ private const val TAG = "DebugActivity"
private const val ROUTE_ROOT = "root"
private const val ROUTE_All_PAGES = "pages"
private const val ROUTE_All_ENTRIES = "entries"
-private const val ROUTE_All_SLICES = "slices"
private const val ROUTE_PAGE = "page"
private const val ROUTE_ENTRY = "entry"
private const val PARAM_NAME_PAGE_ID = "pid"
@@ -87,7 +83,6 @@ class DebugActivity : ComponentActivity() {
composable(route = ROUTE_ROOT) { RootPage() }
composable(route = ROUTE_All_PAGES) { AllPages() }
composable(route = ROUTE_All_ENTRIES) { AllEntries() }
- composable(route = ROUTE_All_SLICES) { AllSlices() }
composable(
route = "$ROUTE_PAGE/{$PARAM_NAME_PAGE_ID}",
arguments = listOf(
@@ -109,8 +104,6 @@ class DebugActivity : ComponentActivity() {
val entryRepository by spaEnvironment.entryRepository
val allPageWithEntry = remember { entryRepository.getAllPageWithEntry() }
val allEntry = remember { entryRepository.getAllEntries() }
- val allSliceEntry =
- remember { entryRepository.getAllEntries().filter { it.hasSliceSupport } }
HomeScaffold(title = "Settings Debug") {
Preference(object : PreferenceModel {
override val title = "List All Pages (${allPageWithEntry.size})"
@@ -120,10 +113,6 @@ class DebugActivity : ComponentActivity() {
override val title = "List All Entries (${allEntry.size})"
override val onClick = navigator(route = ROUTE_All_ENTRIES)
})
- Preference(object : PreferenceModel {
- override val title = "List All Slices (${allSliceEntry.size})"
- override val onClick = navigator(route = ROUTE_All_SLICES)
- })
}
}
@@ -152,18 +141,6 @@ class DebugActivity : ComponentActivity() {
}
}
- @Composable
- fun AllSlices() {
- val entryRepository by spaEnvironment.entryRepository
- val authority = spaEnvironment.sliceProviderAuthorities
- val allSliceEntry =
- remember { entryRepository.getAllEntries().filter { it.hasSliceSupport } }
- RegularScaffold(title = "All Slices (${allSliceEntry.size})") {
- for (entry in allSliceEntry) {
- SliceDemo(sliceUri = Uri.Builder().fromEntry(entry, authority).build())
- }
- }
- }
@Composable
fun OnePage(arguments: Bundle?) {
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/DebugFormat.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/DebugFormat.kt
index 444a3f0fd634..06d105ba61d8 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/DebugFormat.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/DebugFormat.kt
@@ -70,7 +70,6 @@ fun SettingsEntry.debugContent(entryRepository: SettingsEntryRepository): String
"allowSearch = $isAllowSearch",
"isSearchDynamic = $isSearchDataDynamic",
"isSearchMutable = $hasMutableStatus",
- "hasSlice = $hasSliceSupport",
"------ SEARCH ------",
"search_path = $entryPathWithTitle",
searchData?.debugContent() ?: "no search data",
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/search/SpaSearchContract.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/search/SpaSearchContract.kt
index 780933d3c9e2..e5bbb8f027bf 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/search/SpaSearchContract.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/search/SpaSearchContract.kt
@@ -50,7 +50,6 @@ enum class ColumnEnum(val id: String) {
INTENT_TARGET_PACKAGE("intentTargetPackage"),
INTENT_TARGET_CLASS("intentTargetClass"),
INTENT_EXTRAS("intentExtras"),
- SLICE_URI("sliceUri"),
ENTRY_DISABLED("entryDisabled"),
}
@@ -71,7 +70,6 @@ enum class QueryEnum(
ColumnEnum.INTENT_TARGET_PACKAGE,
ColumnEnum.INTENT_TARGET_CLASS,
ColumnEnum.INTENT_EXTRAS,
- ColumnEnum.SLICE_URI,
)
),
SEARCH_DYNAMIC_DATA_QUERY(
@@ -85,7 +83,6 @@ enum class QueryEnum(
ColumnEnum.INTENT_TARGET_PACKAGE,
ColumnEnum.INTENT_TARGET_CLASS,
ColumnEnum.INTENT_EXTRAS,
- ColumnEnum.SLICE_URI,
)
),
SEARCH_IMMUTABLE_STATUS_DATA_QUERY(
@@ -115,7 +112,6 @@ enum class QueryEnum(
ColumnEnum.INTENT_TARGET_PACKAGE,
ColumnEnum.INTENT_TARGET_CLASS,
ColumnEnum.INTENT_EXTRAS,
- ColumnEnum.SLICE_URI,
ColumnEnum.ENTRY_DISABLED,
)
),
@@ -130,7 +126,6 @@ enum class QueryEnum(
ColumnEnum.INTENT_TARGET_PACKAGE,
ColumnEnum.INTENT_TARGET_CLASS,
ColumnEnum.INTENT_EXTRAS,
- ColumnEnum.SLICE_URI,
ColumnEnum.ENTRY_DISABLED,
)
),
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/search/SpaSearchProvider.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/search/SpaSearchProvider.kt
index eacb28c29bc3..65f700cb8b94 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/search/SpaSearchProvider.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/search/SpaSearchProvider.kt
@@ -32,8 +32,6 @@ import com.android.settingslib.spa.framework.common.SettingsEntry
import com.android.settingslib.spa.framework.common.SpaEnvironmentFactory
import com.android.settingslib.spa.framework.util.SESSION_SEARCH
import com.android.settingslib.spa.framework.util.createIntent
-import com.android.settingslib.spa.slice.fromEntry
-
private const val TAG = "SpaSearchProvider"
@@ -217,11 +215,6 @@ class SpaSearchProvider : ContentProvider() {
.add(ColumnEnum.INTENT_TARGET_CLASS.id, spaEnvironment.browseActivityClass?.name)
.add(ColumnEnum.INTENT_EXTRAS.id, marshall(intent.extras))
}
- if (entry.hasSliceSupport)
- row.add(
- ColumnEnum.SLICE_URI.id, Uri.Builder()
- .fromEntry(entry, spaEnvironment.sliceProviderAuthorities)
- )
}
private fun fetchStatusData(entry: SettingsEntry, cursor: MatrixCursor) {
@@ -252,11 +245,6 @@ class SpaSearchProvider : ContentProvider() {
.add(ColumnEnum.INTENT_TARGET_CLASS.id, spaEnvironment.browseActivityClass?.name)
.add(ColumnEnum.INTENT_EXTRAS.id, marshall(intent.extras))
}
- if (entry.hasSliceSupport)
- row.add(
- ColumnEnum.SLICE_URI.id, Uri.Builder()
- .fromEntry(entry, spaEnvironment.sliceProviderAuthorities)
- )
// Fetch status data. We can add runtime arguments later if necessary
val statusData = entry.getStatusData() ?: return
row.add(ColumnEnum.ENTRY_DISABLED.id, statusData.isDisabled)
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-fr-rCA/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-fr-rCA/strings.xml
index a271ff52e801..7e73c4816cc2 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values-fr-rCA/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="no_applications" msgid="5800789569715871963">"Aucune application"</string>
+ <string name="no_applications" msgid="5800789569715871963">"Aucune appli"</string>
<string name="menu_show_system" msgid="906304605807554788">"Afficher le système"</string>
<string name="menu_hide_system" msgid="374571689914923020">"Masquer le système"</string>
<string name="app_permission_summary_allowed" msgid="6115213465364138103">"Autorisé"</string>
diff --git a/packages/SettingsLib/res/layout/zen_mode_duration_dialog.xml b/packages/SettingsLib/res/layout/zen_mode_duration_dialog.xml
index 6552296bc4e4..bc5ec6911939 100644
--- a/packages/SettingsLib/res/layout/zen_mode_duration_dialog.xml
+++ b/packages/SettingsLib/res/layout/zen_mode_duration_dialog.xml
@@ -28,7 +28,7 @@
android:layout_height="match_parent"
android:orientation="vertical">
- <com.android.settingslib.notification.ZenRadioLayout
+ <com.android.settingslib.notification.modes.ZenRadioLayout
android:id="@+id/zen_duration_conditions"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -46,7 +46,7 @@
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"/>
- </com.android.settingslib.notification.ZenRadioLayout>
+ </com.android.settingslib.notification.modes.ZenRadioLayout>
</LinearLayout>
</ScrollView> \ No newline at end of file
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 2db6f627e29e..5632fbd407ab 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Maak dat enige program na eksterne berging geskryf kan word, ongeag manifeswaardes"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Dwing aktiwiteite om verstelbaar te wees"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Maak die groottes van alle aktiwiteite verstelbaar vir veelvuldige vensters, ongeag manifeswaardes."</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"Aktiveer vormvrye vensters"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Aktiveer steun vir eksperimentele vormvrye vensters."</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"Aktiveer vryevormvensters (vorige)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"Aktiveer steun vir eksperimentele vorige vryevormvensters."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Werkskerm-rugsteunwagwoord"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Volle rekenaarrugsteune word nie tans beskerm nie"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Tik om die wagwoord vir volledige rekenaarrugsteune te verander of te verwyder"</string>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index 732ec6fad3ab..4c79154f2ceb 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"የዝርዝር ሰነዶች እሴቶች ግምት ውስጥ ሳያስገባ ማንኛውም መተግበሪያ ወደ ውጫዊ ማከማቻው ለመጻፍ ብቁ ያደርጋል"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"እንቅስቃሴዎች ዳግመኛ እንዲመጣጠኑ አስገድድ"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"የዝርዝር ሰነድ እሴቶች ምንም ይሁኑ ምን ለበርካታ መስኮቶች ሁሉንም እንቅስቃሴዎች መጠናቸው የሚቀየሩ እንዲሆኑ ያደርጋቸዋል።"</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"የነጻ ቅርጽ መስኮቶችን ያንቁ"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"የሙከራ ነፃ መልክ መስኮቶች ድጋፍን አንቃ"</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"ነፃ ቅርጽ መስኮቶች (የቆየ) ያንቁ"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"የሙከራ የቆዩ የነፃ ቅርጽ መስኮቶች ድጋፍን ያንቁ።"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"የዴስክቶፕ መጠባበቂያ ይለፍ ቃል"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"ዴስክቶፕ ሙሉ ምትኬዎች በአሁኑ ሰዓት አልተጠበቁም"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"የዴስክቶፕ ሙሉ ምትኬዎች የይለፍ ቃሉን ለመለወጥ ወይም ለማስወገድ ነካ ያድርጉ"</string>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 2964930736db..3da23c82c1d3 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"تأهيل أي تطبيق بحيث تتم كتابته على وحدة تخزين خارجية، بغض النظر عن قيم البيان"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"فرض إمكانية تغيير حجم الأنشطة"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"السماح بتغيير حجم جميع الأنشطة لتناسب تعدد النوافذ، بغض النظر عن قيم البيان"</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"تفعيل النوافذ الحرة"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"إتاحة استخدام النوافذ الحرة التجريبية"</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"تفعيل النوافذ الحرة (القديمة)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"تفعيل عرض النوافذ الحرة التجريبية القديمة"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"كلمة مرور احتياطية للكمبيوتر"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"النُسخ الاحتياطية الكاملة لسطح المكتب غير محمية في الوقت الحالي"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"انقر لتغيير كلمة مرور النسخ الاحتياطية الكاملة لسطح المكتب أو إزالتها."</string>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index e73462e31ab2..b4f6c45fe466 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"মেনিফেষ্টৰ মান যিয়েই নহওক, বাহ্যিক ষ্ট’ৰেজত লিখিবলৈ যিকোনো এপক উপযুক্ত কৰি তোলে"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"বলেৰে কাৰ্যকলাপসমূহৰ আকাৰ সলনি কৰিব পৰা কৰক"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"মেনিফেষ্টৰ মান যিয়েই নহওক, মাল্টি-ৱিণ্ডৰ বাবে আটাইবোৰ কাৰ্যকলাপৰ আকাৰ সলনি কৰিব পৰা কৰক।"</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"ফ্ৰিফৰ্ম ৱিণ্ড\'জ সক্ষম কৰক"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"পৰীক্ষামূলক ফ্ৰী-ফৰ্ম ৱিণ্ড’বোৰৰ বাবে সহায়তা সক্ষম কৰক৷"</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"ফ্ৰীফৰ্ম ৱিণ্ড’ সক্ষম কৰ (লিগেচী)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"পৰীক্ষামূলক লিগেচী ফ্ৰীফৰ্ম ৱিণ্ড’ৰ সমৰ্থন সক্ষম কৰক।"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"ডেস্কটপ বেকআপ পাছৱৰ্ড"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"ডেস্কটপৰ পূৰ্ণ বেকআপ এতিয়ালৈকে সংৰক্ষিত অৱস্থাত নাই"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"ডেস্কটপ সম্পূৰ্ণ বেকআপৰ বাবে পাছৱৰ্ডটো সলনি কৰিবলৈ বা আঁতৰাবলৈ টিপক"</string>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index 2ae6cd3bf15e..77bfd579b793 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Manifest dəyərindən asılı olmayaraq tətbiqlərin xarici daşıyıcılarda saxlanmasına icazə verilsin"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Çoxpəncərəli rejimdə ölçü dəyişdirilməsi"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Manifest dəyərindən asılı olmayaraq çoxpəncərəli rejimdə pəncərə ölçüsünün dəyişdirilməsinə icazə verilsin"</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"İxtiyari formada pəncərə yaradılsın"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Eksperimental olaraq ixtiyari formada pəncərə yaradılsın"</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"İxtiyari formada pəncərələri (köhnə) aktivləşdirin"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"Təcrübi köhnə ixtiyari formada pəncərələr üçün dəstəyi aktivləşdirin."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Masaüstü rezerv parolu"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Masaüstü tam rezervlər hazırda qorunmayıblar."</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Masaüstünün tam rezerv kopyalanması üçün parolu dəyişmək və ya silmək üçün basın"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index e1e93ef8f1ea..99e31503fb8f 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Omogućava upisivanje svih aplikacija u spoljnu memoriju, bez obzira na vrednosti manifesta"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Prinudno omogući promenu veličine aktivnosti"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Omogućava promenu veličine svih aktivnosti za režim sa više prozora, bez obzira na vrednosti manifesta."</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"Omogući prozore proizvoljnog formata"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Omogućava podršku za eksperimentalne prozore proizvoljnog formata."</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"Omogući prozore proizvoljnog formata (zastarelo)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"Omogućava podršku za zastarele eksperimentalne prozore proizvoljnog formata."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Lozinka rezervne kopije za računar"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Rezervne kopije čitavog sistema trenutno nisu zaštićene"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Dodirnite da biste promenili ili uklonili lozinku za pravljenje rezervnih kopija čitavog sistema na računaru"</string>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index 00eb95d877c1..d66250dfffb6 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Робіць любую праграму даступнай для запісу ў знешняе сховішча, незалежна ад значэнняў маніфеста"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Зрабіць вокны дзеянняў даступнымі для змены памеру"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Зрабіць усе віды дзейнасці даступнымі для змены памеру ў рэжыме некалькіх вокнаў, незалежна ад значэнняў маніфеста."</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"Уключыць адвольную форму вокнаў"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Уключыць падтрымку для эксперыментальнай адвольнай формы акна."</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"Уключыць адвольную форму вокнаў (устарэлая налада)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"Уключыць падтрымку для эксперыментальнай адвольнай формы вокнаў (устарэлая налада)."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Пароль для рэз. копіі ПК"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Поўнае рэзервовае капіраванне працоўнага стала зараз не абаронена"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Краніце, каб змяніць або выдаліць пароль для поўнага рэзервовага капіравання працоўнага стала"</string>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index a2db0f96b74a..706db0785ccc 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Всички приложения ще отговарят на условията да бъдат записвани във външното хранилище независимо от стойностите в манифеста"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Възможност за преоразмеряване на активностите"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Дава възможност за преоразмеряване на всички активности в режима за няколко прозореца независимо от стойностите в манифеста."</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"Активиране на прозорците в свободна форма"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Активиране на поддръжката за експерименталните прозорци в свободна форма."</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"Актив. на прозорците в свободна форма (наследени)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"Активиране на поддръжката за експерименталните наследени прозорци в свободна форма."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Парола за резервни копия"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Понастоящем пълните резервни копия за настолен компютър не са защитени"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Докоснете, за да промените или премахнете паролата за пълни резервни копия на настолния компютър"</string>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index f8118f4a0f69..0e83ff21fd65 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"ম্যানিফেস্ট মানের নির্বিশেষে যেকোনও অ্যাপকে এক্সটারনাল স্টোরেজে ইনস্টল করার উপযুক্ত বানায়"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"আকার পরিবর্তনযোগ্য করার জন্য ক্রিয়াকলাপগুলিকে জোর করুন"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"ম্যানিফেস্ট মানগুলির নির্বিশেষে মাল্টি-উইন্ডোর জন্য সমস্ত ক্রিয়াকলাপগুলির আকার পরিবর্তনযোগ্য করুন৷"</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"ফ্রি-ফর্ম উইন্ডো চালু করুন"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"পরীক্ষামূলক ফ্রি-ফর্ম উইন্ডোগুলির জন্য সহায়তা সক্ষম করুন৷"</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"ফ্রিফর্ম উইন্ডো (লিগ্যাসি) চালু করুন"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"এক্সপেরিমেন্টাল ফ্রিফর্ম উইন্ডোর জন্য সহায়তা চালু করুন।"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"ডেস্কটপ ব্যাকআপ পাসওয়ার্ড"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"ডেস্কটপ পূর্ণ ব্যাকআপ বর্তমানে সুরক্ষিত নয়"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"ডেস্কটপের সম্পূর্ণ ব্যাকআপের পাসওয়ার্ডটি পরিবর্তন করতে বা মুছে ফেলতে আলতো চাপুন"</string>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index 2288f05140e5..fd2b1214ee9d 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Omogućava upisivanje svih aplikacija u vanjsku pohranu, bez obzira na prikazane vrijednosti"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Nametni aktivnostima mijenjanje veličina"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Omogućava mijenjanje veličine svih aktivnosti za prikaz s više prozora, bez obzira na prikazane vrijednosti"</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"Omogući prozore nepravilnih oblika"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Omogućava podršku za eksperimentalne prozore nepravilnih oblika."</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"Omogući prilagodljive prozore (staro)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"Omogućite podršku za eksperimentalne stare prilagodljive prozore."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Lozinka sigurnosne kopije za računar"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Potpune sigurnosne kopije za računare trenutno nisu zaštićene"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Dodirnite da promijenite ili uklonite lozinku za potpune rezervne kopije s radne površine"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 61a6e82f19c4..e685afc25f5c 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Permet que qualsevol aplicació es pugui escriure en un dispositiu d’emmagatzematge extern, independentment dels valors del manifest"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Força l\'ajust de la mida de les activitats"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Permet ajustar la mida de totes les activitats per al mode multifinestra, independentment dels valors del manifest"</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"Activa les finestres amb format lliure"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Activa la compatibilitat amb finestres experimentals amb format lliure"</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"Activa les finestres amb format lliure (heretat)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"Activa la compatibilitat amb les finestres de format lliure heretades i experimentals."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Contrasenya per a còpies d\'ordinador"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Les còpies de seguretat completes d\'ordinador no estan protegides"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Toca per canviar o suprimir la contrasenya per a les còpies de seguretat completes de l\'ordinador"</string>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index 34444308495e..c8c4869f55c9 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Každou aplikaci bude možné zapsat do externího úložiště, bez ohledu na hodnoty manifestu"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Vynutit možnost změny velikosti aktivit"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Umožní změnu velikosti všech aktivit na několik oken (bez ohledu na hodnoty manifestu)"</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"Aktivovat okna s volným tvarem"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Aktivuje podporu experimentálních oken s volným tvarem"</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"Aktivovat okna s volným tvarem (starší nastavení)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"Aktivuje podporu starších experimentálních oken s volným tvarem."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Heslo pro zálohy v počítači"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Úplné zálohy v počítači nejsou v současné době chráněny"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Tuto možnost vyberte, chcete-li změnit nebo odebrat heslo pro úplné zálohy do počítače"</string>
diff --git a/packages/SettingsLib/res/values-da/arrays.xml b/packages/SettingsLib/res/values-da/arrays.xml
index 3c5135bb87e8..3d2d6c7a5681 100644
--- a/packages/SettingsLib/res/values-da/arrays.xml
+++ b/packages/SettingsLib/res/values-da/arrays.xml
@@ -156,13 +156,13 @@
<item msgid="1241278021345116816">"Optimeret til lydkvalitet (990 kbps/909 kbps)"</item>
<item msgid="3523665555859696539">"Afbalancer lyd- og forbindelseskvalitet (660 kbps/606 kbps)"</item>
<item msgid="886408010459747589">"Optimeret til forbindelseskvalitet (330 kbps/303 kbps)"</item>
- <item msgid="3808414041654351577">"Bedste resultat (tilpasset bithastighed)"</item>
+ <item msgid="3808414041654351577">"Bedste resultat (adaptiv bithastighed)"</item>
</string-array>
<string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
<item msgid="804499336721569838">"Optimeret til lydkvalitet"</item>
<item msgid="7451422070435297462">"Afbalancer lyd- og forbindelseskvalitet"</item>
<item msgid="6173114545795428901">"Optimeret til forbindelseskvalitet"</item>
- <item msgid="4349908264188040530">"Bedste resultat (tilpasset bithastighed)"</item>
+ <item msgid="4349908264188040530">"Bedste resultat (adaptiv bithastighed)"</item>
</string-array>
<string-array name="bluetooth_audio_active_device_summaries">
<item msgid="8019740759207729126"></item>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index 1bff907a86c7..a7cbcd47e7b8 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Gør det muligt at overføre enhver app til et eksternt lager uafhængigt af manifestværdier"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Gennemtving, at aktiviteter kan tilpasses"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Tillad, at alle aktiviteter kan tilpasses flere vinduer uafhængigt af manifestværdier"</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"Aktivér vinduer i frit format"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Aktivér understøttelse af eksperimentelle vinduer i frit format"</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"Aktivér vinduer i frit format (forældet)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"Aktivér understøttelse af eksperimentelle forældede vinduer i frit format."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Kode til lokal sikkerhedskopi"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Lokale komplette backups er i øjeblikket ikke beskyttet"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Tryk for at skifte eller fjerne adgangskoden til fuld lokal sikkerhedskopiering"</string>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 64139a912fc1..946159db5fdb 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Jede App kann, ungeachtet der Manifestwerte, in den externen Speicher geschrieben werden"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Aktivitätengröße darf immer angepasst werden"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Die Größe aller Aktivitäten darf, ungeachtet der Manifestwerte, für die Mehrfensterdarstellung angepasst werden"</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"Freiform-Fenster zulassen"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Unterstützung für experimentelle Freiform-Fenster aktivieren"</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"Freiform-Fenster zulassen (Legacy)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"Unterstützung für experimentelle Legacy-Freiform-Fenster aktivieren."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Passwort für Desktop-Sicherung"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Vollständige Desktop-Sicherungen sind momentan nicht passwortgeschützt"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Zum Ändern oder Entfernen des Passworts für vollständige Desktop-Sicherungen tippen"</string>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index f8a6944d84d2..5b156bf5b71d 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Κάνει κάθε εφαρμογή κατάλληλη για εγγραφή σε εξωτερικό αποθηκευτικό χώρο, ανεξάρτητα από τις τιμές του μανιφέστου"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Αναγκαστική δυνατότητα αλλαγής μεγέθους δραστηριοτήτων"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Να έχουν όλες οι δραστηριότητες δυνατότητα αλλαγής μεγέθους για την προβολή πολλαπλών παραθύρων, ανεξάρτητα από τις τιμές του μανιφέστου."</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"Ενεργοποίηση παραθύρων ελεύθερης μορφής"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Ενεργοποίηση υποστήριξης για πειραματικά παράθυρα ελεύθερης μορφής."</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"Ενεργ. παραθύρων ελεύθερης μορφής (παλαιού τύπου)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"Ενεργοποίηση υποστήριξης για πειραματικά παράθυρα ελεύθερης μορφής παλαιού τύπου."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Εφ/κός κωδικός desktop"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Τα πλήρη αντίγραφα ασφαλείας επιφάνειας εργασίας δεν προστατεύονται αυτή τη στιγμή"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Πατήστε για αλλαγή ή κατάργηση του κωδικού πρόσβασης για τα πλήρη αντίγραφα ασφαλείας επιφάνειας εργασίας"</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index a6367f1059b4..b0b3de1e47b1 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Makes any app eligible to be written to external storage, regardless of manifest values"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Force activities to be resizeable"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Make all activities resizeable for multi-window, regardless of manifest values."</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"Enable freeform windows"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Enable support for experimental freeform windows."</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"Enable freeform windows (legacy)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"Enable support for experimental legacy freeform windows."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Desktop backup password"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Desktop full backups aren\'t currently protected"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Tap to change or remove the password for desktop full backups"</string>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index 975cc5ee7b88..a77d6c66447d 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -430,8 +430,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Makes any app eligible to be written to external storage, regardless of manifest values"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Force activities to be resizable"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Make all activities resizable for multi-window, regardless of manifest values."</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"Enable freeform windows"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Enable support for experimental freeform windows."</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"Enable freeform windows (legacy)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"Enable support for experimental legacy freeform windows."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Desktop backup password"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Desktop full backups aren’t currently protected"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Tap to change or remove the password for desktop full backups"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index a6367f1059b4..b0b3de1e47b1 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Makes any app eligible to be written to external storage, regardless of manifest values"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Force activities to be resizeable"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Make all activities resizeable for multi-window, regardless of manifest values."</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"Enable freeform windows"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Enable support for experimental freeform windows."</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"Enable freeform windows (legacy)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"Enable support for experimental legacy freeform windows."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Desktop backup password"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Desktop full backups aren\'t currently protected"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Tap to change or remove the password for desktop full backups"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index a6367f1059b4..b0b3de1e47b1 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Makes any app eligible to be written to external storage, regardless of manifest values"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Force activities to be resizeable"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Make all activities resizeable for multi-window, regardless of manifest values."</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"Enable freeform windows"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Enable support for experimental freeform windows."</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"Enable freeform windows (legacy)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"Enable support for experimental legacy freeform windows."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Desktop backup password"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Desktop full backups aren\'t currently protected"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Tap to change or remove the password for desktop full backups"</string>
diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml
index 7411487899f3..8d6520f992b2 100644
--- a/packages/SettingsLib/res/values-en-rXC/strings.xml
+++ b/packages/SettingsLib/res/values-en-rXC/strings.xml
@@ -430,8 +430,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‎‏‎‎‎‎‎‏‏‎‎‏‎‏‏‎‎‏‎‏‎‎‎‏‎‏‏‏‏‎‏‎‏‏‎‎‏‏‎‏‏‎‎‎‎‏‎‎‏‎‏‏‏‎‎Makes any app eligible to be written to external storage, regardless of manifest values‎‏‎‎‏‎"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‎‎‏‏‎‎‏‎‎‎‏‏‎‎‏‏‎‏‎‏‎‏‏‎‎‏‎‏‏‎‎‏‏‎‎‎‎‎‏‎‎‎‎‎‎‏‎‎‎‏‏‎‎‎‏‏‎‏‏‎‎Force activities to be resizable‎‏‎‎‏‎"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‎‎‏‎‏‎‎‎‏‏‏‏‏‎‎‏‏‏‎‏‎‏‎‎‏‎‎‏‎‏‎‎‎‏‎‏‎‏‏‎‎‏‎‎‏‏‎‏‎‏‎‎‏‏‎‏‎‏‏‎‎Make all activities resizable for multi-window, regardless of manifest values.‎‏‎‎‏‎"</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‏‎‎‏‎‏‏‏‎‏‎‏‏‎‎‎‎‏‎‎‏‎‎‎‏‏‎‏‎‎‎‎‏‏‎‏‎‎‏‎‏‏‎‏‎‏‏‎‎‏‏‎‎‎‎‎‏‏‎‏‎Enable freeform windows‎‏‎‎‏‎"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‏‎‎‏‎‏‎‎‏‏‎‎‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‏‏‎‏‎‏‏‏‎‎‏‏‏‎‎‏‎‎‏‏‎‎‏‎‎‏‎‏‎‏‏‎Enable support for experimental freeform windows.‎‏‎‎‏‎"</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‎‏‏‎‏‏‎‎‎‎‏‎‏‎‎‏‏‎‎‎‏‏‏‏‎‎‎‏‏‎‎‎‏‎‎‎‎‎‏‎‎‏‎‏‏‎‏‎‏‏‏‎‎‏‎‎Enable freeform windows (legacy)‎‏‎‎‏‎"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‏‏‏‏‎‎‎‏‏‏‏‎‏‏‏‎‎‏‎‎‏‎‏‎‏‎‎‏‏‏‎‎‏‎‎‏‎‏‏‎‏‎‏‏‏‎‎‎‎‎‏‎‏‏‏‎‏‏‏‎‎Enable support for experimental legacy freeform windows.‎‏‎‎‏‎"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‎‎‎‎‎‏‎‎‎‏‎‎‏‎‏‎‏‏‏‎‎‏‎‎‏‎‎‏‏‏‎‏‎‎‏‎‏‎‏‎‎‏‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‏‎‏‎Desktop backup password‎‏‎‎‏‎"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‏‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‏‎‏‎‎‏‏‏‏‏‎‏‏‏‎‎‎‏‏‏‎‏‏‏‎‏‏‎‏‎‎‏‏‏‎‏‏‏‏‎‎‏‎‎Desktop full backups aren’t currently protected‎‏‎‎‏‎"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‎‏‏‏‏‎‏‏‎‎‎‏‏‏‎‎‎‎‎‎‏‏‎‎‎‎‎‏‎‏‎‏‎‏‏‏‏‏‎‎‎‏‏‎‏‏‎‎‏‎‏‎‏‎‏‎‏‏‏‏‎Tap to change or remove the password for desktop full backups‎‏‎‎‏‎"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index 3c95fd29ca6f..5f9edd6be19a 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Cualquier app puede escribirse en un almacenamiento externo, sin importar los valores del manifiesto"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Forzar actividades para que cambien de tamaño"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Permitir que todas las actividades puedan cambiar de tamaño para el modo multiventana, sin importar los valores del manifiesto."</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"Habilitar ventanas de forma libre"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Permite la compatibilidad con ventanas de forma libre experimentales."</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"Habilitar ventanas de formato libre (heredado)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"Permitir la compatibilidad con ventanas de formato libre experimentales (heredado)"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Contraseñas"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Tus copias de seguridad de escritorio no están protegidas por contraseña"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Presiona para cambiar o quitar la contraseña de las copias de seguridad completas de tu escritorio."</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index 28bfb383eac6..fdba8c4c2d47 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Permite que cualquier aplicación se pueda escribir en un almacenamiento externo independientemente de los valores de manifiesto"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Forzar que las actividades puedan cambiar de tamaño"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Permite que todas las actividades puedan cambiar de tamaño en multiventana independientemente de los valores de manifiesto"</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"Habilitar ventanas de forma libre"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Permite la compatibilidad con ventanas de forma libre experimentales"</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"Habilitar ventanas de forma libre (antiguo)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"Habilita la compatibilidad con ventanas de forma libre antiguas y experimentales."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Contraseña para copias de ordenador"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Las copias de seguridad completas de ordenador no están protegidas"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Toca para cambiar o quitar la contraseña de las copias de seguridad completas del escritorio"</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index 25bc4874a17a..feca80f62ab2 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Lubab mis tahes rakendusi kirjutada välisesse salvestusruumi manifesti väärtustest olenemata"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Muuda tegevuste suurused muudetavaks"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Muudetakse kõigi tegevuste suurused mitme aknaga vaates muudetavaks (manifesti väärtustest olenemata)."</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"Luba vabas vormis aknad"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Lubatakse katseliste vabavormis akende tugi."</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"Luba vabas vormis aknad (pärand)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"Lubatakse katseliste pärand vabas vormis akende tugi."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Arvutivarunduse parool"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Täielikud arvutivarundused pole praegu kaitstud"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Puudutage täielike arvutivarunduste parooli muutmiseks või eemaldamiseks"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index 4b9cb836185a..ae783f2fed47 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Aplikazioek kanpoko memorian idatz dezakete, ezarritako balioak kontuan izan gabe"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Behartu jardueren tamaina doitu ahal izatera"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Eman aukera jarduera guztien tamaina doitzeko, leiho batean baino gehiagotan erabili ahal izan daitezen, ezarritako balioak kontuan izan gabe"</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"Gaitu estilo libreko leihoak"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Onartu estilo libreko leiho esperimentalak"</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"Gaitu estilo libreko leihoak (aurreko bertsiokoak)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"Onartu aurreko bertsioko estilo libreko leiho esperimentalak."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Babeskopien pasahitz lokala"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Une honetan, ordenagailuko babeskopia osoak ez daude babestuta"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Ordenagailuko eduki guztiaren babeskopia egiteko erabiltzen den pasahitza aldatzeko edo kentzeko, sakatu hau"</string>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index 27e203b91b53..7a296f2ce098 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"بدون توجه به مقادیر آشکار، هر برنامه‌ای را برای نوشتن در حافظه خارجی واجد شرایط می‌کند"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"اجبار فعالیت‌ها به قابل تغییر اندازه بودن"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"بدون توجه به مقادیر مانیفست، اندازه همه فعالیت‌ها برای حالت چند پنجره‌ای می‌تواند تغییر کند."</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"فعال کردن پنجره‌های آزاد"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"فعال کردن پشتیبانی برای پنجره‌های آزاد آزمایشی."</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"فعال کردن پنجره‌های با قالب آزاد (قدیمی)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"فعال کردن پشتیبانی از پنجره‌های با قالب آزاد قدیمی آزمایشی."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"گذرواژه پشتیبان‌گیری محلی"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"پشتیبان‌گیری کامل رایانه درحال حاضر محافظت نمی‌شود"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"برای تغییر یا حذف گذرواژه برای نسخه‌های پشتیبان کامل رایانه‌ای تک‌ضرب بزنید"</string>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index a8222b9fee4c..978b128547f5 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Mahdollistaa sovelluksen tietojen tallentamisen ulkoiseen tallennustilaan luetteloarvoista riippumatta"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Pakota kaikki toiminnot hyväksymään koon muutos"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Pakota kaikki toiminnot hyväksymään koon muuttaminen usean ikkunan tilassa luettelon arvoista riippumatta"</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"Ota käyttöön vapaamuotoiset ikkunat"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Ota kokeellisten vapaamuotoisten ikkunoiden tuki käyttöön"</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"Ota vapaamuotoiset ikkunat käyttöön (vanha)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"Ota kokeellinen vapaamuotoisten ikkunoiden tuki käyttöön (vanha)."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Varmuuskop. salasana"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Tietokoneen kaikkien tietojen varmuuskopiointia ei ole tällä hetkellä suojattu"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Vaihda tai poista tietokoneen kaikkien tietojen varmuuskopioinnin salasana koskettamalla."</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index cdc1e44ae3bf..b62064947b6b 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -182,8 +182,8 @@
<string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Réseau ouvert"</string>
<string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Réseau sécurisé"</string>
<string name="process_kernel_label" msgid="950292573930336765">"Système d\'exploitation Android"</string>
- <string name="data_usage_uninstalled_apps" msgid="1933665711856171491">"Applications supprimées"</string>
- <string name="data_usage_uninstalled_apps_users" msgid="5533981546921913295">"Applications et utilisateurs supprimés"</string>
+ <string name="data_usage_uninstalled_apps" msgid="1933665711856171491">"Applis supprimées"</string>
+ <string name="data_usage_uninstalled_apps_users" msgid="5533981546921913295">"Applis et utilisateurs supprimés"</string>
<string name="data_usage_ota" msgid="7984667793701597001">"Mises à jour du système"</string>
<string name="tether_settings_title_usb" msgid="3728686573430917722">"Partage de connexion par USB"</string>
<string name="tether_settings_title_wifi" msgid="4803402057533895526">"Point d\'accès Wi-Fi mobile"</string>
@@ -241,7 +241,7 @@
<string name="category_clone" msgid="1554511758987195974">"Cloner"</string>
<string name="development_settings_title" msgid="140296922921597393">"Options pour les développeurs"</string>
<string name="development_settings_enable" msgid="4285094651288242183">"Activer les options pour les développeurs"</string>
- <string name="development_settings_summary" msgid="8718917813868735095">"Définir les options pour le développement de l\'application"</string>
+ <string name="development_settings_summary" msgid="8718917813868735095">"Définir les options pour le développement de l\'appli"</string>
<string name="development_settings_not_available" msgid="355070198089140951">"Les options proposées aux développeurs ne sont pas disponibles pour cet utilisateur."</string>
<string name="vpn_settings_not_available" msgid="2894137119965668920">"Les paramètres de RPV ne sont pas disponibles pour cet utilisateur"</string>
<string name="tethering_settings_not_available" msgid="266821736434699780">"Les paramètres de partage de connexion ne sont pas disponibles pour cet utilisateur"</string>
@@ -288,8 +288,8 @@
<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\'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="mock_location_app_not_set" msgid="6972032787262831155">"Aucune appli de position fictive définie"</string>
+ <string name="mock_location_app_set" msgid="4706722469342913843">"Appli de position fictive : <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="debug_networking_category" msgid="6829757985772659599">"Réseautage"</string>
<string name="wifi_display_certification" msgid="1805579519992520381">"Certification de l\'affichage sans fil"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Autoriser enreg. données Wi-Fi détaillées"</string>
@@ -343,30 +343,30 @@
<string name="mobile_data_always_on_summary" msgid="1112156365594371019">"Toujours garder les données cellulaires actives, même lorsque le Wi-Fi est activé (pour la commutation rapide entre les réseaux)."</string>
<string name="tethering_hardware_offload_summary" msgid="7801345335142803029">"Utiliser l\'accélération matérielle du partage de connexion si possible"</string>
<string name="adb_warning_title" msgid="7708653449506485728">"Autoriser le débogage USB?"</string>
- <string name="adb_warning_message" msgid="8145270656419669221">"Le débogage USB est conçu uniquement pour le développement. Utilisez-le pour copier des données entre votre ordinateur et votre appareil, installer des applications sur votre appareil sans notification et lire les données de journal."</string>
+ <string name="adb_warning_message" msgid="8145270656419669221">"Le débogage USB est conçu uniquement pour le développement. Utilisez-le pour copier des données entre votre ordinateur et votre appareil, installer des applis sur votre appareil sans notification et lire les données de journal."</string>
<string name="adbwifi_warning_title" msgid="727104571653031865">"Autoriser le débogage sans fil?"</string>
- <string name="adbwifi_warning_message" msgid="8005936574322702388">"Le débogage sans fil est conçu uniquement aux fin de conception. Utilisez-le pour copier des données entre votre ordinateur et votre appareil, installer des applications sur votre appareil sans notification et lire les données de journal."</string>
+ <string name="adbwifi_warning_message" msgid="8005936574322702388">"Le débogage sans fil est conçu uniquement aux fin de conception. Utilisez-le pour copier des données entre votre ordinateur et votre appareil, installer des applis sur votre appareil sans notification et lire les données de journal."</string>
<string name="adb_keys_warning_message" msgid="2968555274488101220">"Voulez-vous vraiment désactiver l\'accès au débogage USB de tous les ordinateurs précédemment autorisés?"</string>
<string name="dev_settings_warning_title" msgid="8251234890169074553">"Activer les paramètres de développement?"</string>
- <string name="dev_settings_warning_message" msgid="37741686486073668">"Ces paramètres sont en cours de développement. Ils peuvent endommager votre appareil et les applications qui s\'y trouvent, ou provoquer leur dysfonctionnement."</string>
+ <string name="dev_settings_warning_message" msgid="37741686486073668">"Ces paramètres sont en cours de développement. Ils peuvent endommager votre appareil et les applis qui s\'y trouvent, ou provoquer leur dysfonctionnement."</string>
<string name="verify_apps_over_usb_title" msgid="6031809675604442636">"Vérifier les applis par USB"</string>
- <string name="verify_apps_over_usb_summary" msgid="1317933737581167839">"Vérifier que les applications installées par ADB/ADT ne présentent pas de comportement dangereux."</string>
+ <string name="verify_apps_over_usb_summary" msgid="1317933737581167839">"Vérifier que les applis installées par ADB/ADT ne présentent pas de comportement dangereux."</string>
<string name="bluetooth_show_devices_without_names_summary" msgid="780964354377854507">"Les appareils Bluetooth sans nom (adresses MAC seulement) seront affichés"</string>
<string name="bluetooth_disable_absolute_volume_summary" msgid="2006309932135547681">"Désactive la fonctionnalité de volume absolu par Bluetooth en cas de problème de volume sur les appareils à distance, par exemple si le volume est trop élevé ou s\'il ne peut pas être contrôlé."</string>
<string name="bluetooth_enable_gabeldorsche_summary" msgid="2054730331770712629">"Active la pile de la fonctionnalité Bluetooth Gabeldorsche."</string>
<string name="enhanced_connectivity_summary" msgid="1576414159820676330">"Active la fonctionnalité Connectivité améliorée."</string>
<string name="enable_terminal_title" msgid="3834790541986303654">"Terminal local"</string>
- <string name="enable_terminal_summary" msgid="2481074834856064500">"Activer l\'application Terminal permettant l\'accès au shell local"</string>
+ <string name="enable_terminal_summary" msgid="2481074834856064500">"Activer l\'appli Terminal permettant l\'accès au shell local"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"Vérification HDCP"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"Configurer vérification HDCP"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"Débogage"</string>
- <string name="debug_app" msgid="8903350241392391766">"Sélectionner une application à déboguer"</string>
- <string name="debug_app_not_set" msgid="1934083001283807188">"Aucune application à déboguer définie"</string>
- <string name="debug_app_set" msgid="6599535090477753651">"Application à déboguer : <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
- <string name="select_application" msgid="2543228890535466325">"Sél. application"</string>
+ <string name="debug_app" msgid="8903350241392391766">"Sélectionner une appli à déboguer"</string>
+ <string name="debug_app_not_set" msgid="1934083001283807188">"Aucune appli à déboguer définie"</string>
+ <string name="debug_app_set" msgid="6599535090477753651">"Appli à déboguer : <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="select_application" msgid="2543228890535466325">"Sél. appli"</string>
<string name="no_application" msgid="9038334538870247690">"Aucune"</string>
<string name="wait_for_debugger" msgid="7461199843335409809">"Attendre l\'intervention du débogueur"</string>
- <string name="wait_for_debugger_summary" msgid="6846330006113363286">"Avant de s\'exécuter, l\'application déboguée doit attendre que le débogueur soit attaché."</string>
+ <string name="wait_for_debugger_summary" msgid="6846330006113363286">"Avant de s\'exécuter, l\'appli déboguée doit attendre que le débogueur soit attaché."</string>
<string name="debug_input_category" msgid="7349460906970849771">"Entrée"</string>
<string name="debug_drawing_category" msgid="5066171112313666619">"Dessin"</string>
<string name="debug_hw_drawing_category" msgid="5830815169336975162">"Accélération matérielle"</string>
@@ -401,7 +401,7 @@
<string name="transparent_navigation_bar_summary" msgid="5454359021817330722">"Rendre la couleur d\'arrière-plan de la barre de navigation transparente par défaut"</string>
<string name="window_blurs" msgid="6831008984828425106">"Autoriser le flou au niveau des fenêtres"</string>
<string name="force_msaa" msgid="4081288296137775550">"Forcer MSAA 4x"</string>
- <string name="force_msaa_summary" msgid="9070437493586769500">"Activer MSAA 4x dans les applications OpenGL ES 2.0"</string>
+ <string name="force_msaa_summary" msgid="9070437493586769500">"Activer MSAA 4x dans les applis OpenGL ES 2.0"</string>
<string name="show_non_rect_clip" msgid="7499758654867881817">"Déboguer opérations de découpage non rectangulaire"</string>
<string name="track_frame_time" msgid="522674651937771106">"Rendu HWUI du profil"</string>
<string name="enable_gpu_debug_layers" msgid="4986675516188740397">"Activer couches débogage GPU"</string>
@@ -424,20 +424,20 @@
<string name="transition_animation_scale_title" msgid="1278477690695439337">"Éch. d\'animation des transitions"</string>
<string name="animator_duration_scale_title" msgid="7082913931326085176">"Échelle durée animation"</string>
<string name="overlay_display_devices_title" msgid="5411894622334469607">"Simuler affich. secondaires"</string>
- <string name="debug_applications_category" msgid="5394089406638954196">"Applications"</string>
+ <string name="debug_applications_category" msgid="5394089406638954196">"Applis"</string>
<string name="immediately_destroy_activities" msgid="1826287490705167403">"Ne pas conserver activités"</string>
<string name="immediately_destroy_activities_summary" msgid="6289590341144557614">"Supprimer immédiatement les activités abandonnées"</string>
<string name="app_process_limit_title" msgid="8361367869453043007">"Limite processus arr.-plan"</string>
<string name="show_all_anrs" msgid="9160563836616468726">"Afficher ANR arrière-plan"</string>
- <string name="show_all_anrs_summary" msgid="8562788834431971392">"Afficher le message « L\'application ne répond plus » pour les applications en arrière-plan"</string>
+ <string name="show_all_anrs_summary" msgid="8562788834431971392">"Afficher le message « L\'appli ne répond plus » pour les applis en arrière-plan"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"Affich. avertiss. canal notification"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Afficher avertiss. à l\'écran quand une appli présente une notif. sans canal valide"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"Forcer l\'autor. d\'applis sur stockage externe"</string>
- <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Rend possible l\'enregistrement de toute application sur un espace de stockage externe, indépendamment des valeurs du fichier manifeste"</string>
+ <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Rend possible l\'enregistrement de toute appli sur un espace de stockage externe, indépendamment des valeurs du fichier manifeste"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Forcer les activités à être redimensionnables"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Permet de redimensionner toutes les activités pour le mode multi-fenêtre, indépendamment des valeurs du fichier manifeste."</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"Activer les fenêtres de forme libre"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Activer la compatibilité avec les fenêtres de forme libre expérimentales."</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"Activer fenêtres de forme libre (patrimoniales)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"Activer la prise en charge des fenêtres de forme libre patrimoniales expérimentales."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Mot de passe sauvegarde PC"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Les sauvegardes complètes sur PC ne sont pas protégées actuellement"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Touchez pour modifier ou supprimer le mot de passe utilisé pour les sauvegardes complètes sur ordinateur."</string>
@@ -455,14 +455,14 @@
<item msgid="4548987861791236754">"Couleurs naturelles, comme l\'œil les voit"</item>
<item msgid="1282170165150762976">"Couleurs optimisées pour le contenu numérique"</item>
</string-array>
- <string name="inactive_apps_title" msgid="5372523625297212320">"Applications en veille"</string>
- <string name="inactive_app_inactive_summary" msgid="3161222402614236260">"Application inactive. Touchez ici pour l\'activer."</string>
- <string name="inactive_app_active_summary" msgid="8047630990208722344">"Application active. Touchez ici pour la désactiver."</string>
- <string name="standby_bucket_summary" msgid="5128193447550429600">"État de l\'application en veille :<xliff:g id="BUCKET"> %s</xliff:g>"</string>
+ <string name="inactive_apps_title" msgid="5372523625297212320">"Applis en veille"</string>
+ <string name="inactive_app_inactive_summary" msgid="3161222402614236260">"Appli inactive. Touchez ici pour l\'activer."</string>
+ <string name="inactive_app_active_summary" msgid="8047630990208722344">"Appli active. Touchez ici pour la désactiver."</string>
+ <string name="standby_bucket_summary" msgid="5128193447550429600">"État de l\'appli en veille :<xliff:g id="BUCKET"> %s</xliff:g>"</string>
<string name="transcode_settings_title" msgid="2581975870429850549">"Paramètres de transcodage des éléments multimédias"</string>
<string name="transcode_user_control" msgid="6176368544817731314">"Remplacer les valeurs par défaut de transcodage"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Activer le transcodage"</string>
- <string name="transcode_default" msgid="3784803084573509491">"Présumer que les applications prennent en charge les formats modernes"</string>
+ <string name="transcode_default" msgid="3784803084573509491">"Présumer que les applis prennent en charge les formats modernes"</string>
<string name="transcode_notification" msgid="5560515979793436168">"Afficher les notifications de transcodage"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"Désactiver le cache de transcodage"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Services en cours d\'exécution"</string>
@@ -547,9 +547,9 @@
<string name="retail_demo_reset_title" msgid="1866911701095959800">"Mot de passe obligatoire"</string>
<string name="active_input_method_subtypes" msgid="4232680535471633046">"Modes de saisie actifs"</string>
<string name="use_system_language_to_select_input_method_subtypes" msgid="4865195835541387040">"Utiliser les langues du système"</string>
- <string name="failed_to_open_app_settings_toast" msgid="764897252657692092">"Échec de l\'ouverture des paramètres de l\'application <xliff:g id="SPELL_APPLICATION_NAME">%1$s</xliff:g>."</string>
- <string name="ime_security_warning" msgid="6547562217880551450">"Ce mode de saisie est susceptible d\'enregistrer le texte que vous saisissez, y compris vos données personnelles, telles que les mots de passe et les numéros de carte de paiement. Il provient de l\'application <xliff:g id="IME_APPLICATION_NAME">%1$s</xliff:g>. Voulez-vous vraiment l\'activer?"</string>
- <string name="direct_boot_unaware_dialog_message" msgid="7845398276735021548">"Remarque : Après un redémarrage, vous ne pouvez pas lancer cette application tant que vous n\'avez pas déverrouillé votre téléphone."</string>
+ <string name="failed_to_open_app_settings_toast" msgid="764897252657692092">"Échec de l\'ouverture des paramètres de l\'appli <xliff:g id="SPELL_APPLICATION_NAME">%1$s</xliff:g>."</string>
+ <string name="ime_security_warning" msgid="6547562217880551450">"Ce mode de saisie est susceptible d\'enregistrer le texte que vous saisissez, y compris vos données personnelles, telles que les mots de passe et les numéros de carte de paiement. Il provient de l\'appli <xliff:g id="IME_APPLICATION_NAME">%1$s</xliff:g>. Voulez-vous vraiment l\'activer?"</string>
+ <string name="direct_boot_unaware_dialog_message" msgid="7845398276735021548">"Remarque : Après un redémarrage, vous ne pouvez pas lancer cette appli tant que vous n\'avez pas déverrouillé votre téléphone."</string>
<string name="ims_reg_title" msgid="8197592958123671062">"État d\'enregistrement IMS"</string>
<string name="ims_reg_status_registered" msgid="884916398194885457">"Enregistré"</string>
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Non enregistré"</string>
@@ -567,7 +567,7 @@
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmes et rappels"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Autoriser la création d\'alarmes et de rappels"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmes et rappels"</string>
- <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Autorisez cette application à créer des alarmes et à programmer des actions urgentes. Cela permet à l’application de s\'exécuter en arrière-plan, ce qui peut nécessiter plus de pile.\n\nSi cette autorisation est désactivée, les alarmes existantes et les événements en temps réel programmés par cette application ne fonctionneront pas."</string>
+ <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Autorisez cette appli à créer des alarmes et à programmer des actions urgentes. Cela permet à l’appli de s\'exécuter en arrière-plan, ce qui peut nécessiter plus de pile.\n\nSi cette autorisation est désactivée, les alarmes existantes et les événements en temps réel programmés par cette appli ne fonctionneront pas."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"horaire, alarme, rappel, horloge"</string>
<string name="zen_mode_settings_title" msgid="7374070457626419755">"Ne pas déranger"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Activer"</string>
@@ -619,20 +619,20 @@
<string name="blob_expires_text" msgid="7882727111491739331">"Expirent le <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="shared_data_delete_failure_text" msgid="3842701391009628947">"Une erreur s\'est produite lors de la suppression des données partagées."</string>
<string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"Il n\'y a aucun bail octroyé pour ces données partagées. Souhaitez-vous les supprimer?"</string>
- <string name="accessor_info_title" msgid="8289823651512477787">"Applications qui partagent des données"</string>
- <string name="accessor_no_description_text" msgid="7510967452505591456">"Aucune description fournie par l\'application."</string>
+ <string name="accessor_info_title" msgid="8289823651512477787">"Applis qui partagent des données"</string>
+ <string name="accessor_no_description_text" msgid="7510967452505591456">"Aucune description fournie par l\'appli."</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"Le bail expire le <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="delete_blob_text" msgid="2819192607255625697">"Supprimer les données partagées"</string>
<string name="delete_blob_confirmation_text" msgid="7807446938920827280">"Voulez-vous vraiment supprimer ces données partagées?"</string>
- <string name="user_add_user_item_summary" msgid="5748424612724703400">"Les utilisateurs disposent de leurs propres applications et de leur propre contenu."</string>
- <string name="user_add_profile_item_summary" msgid="5418602404308968028">"Vous pouvez limiter l\'accès aux applications et au contenu depuis votre compte."</string>
+ <string name="user_add_user_item_summary" msgid="5748424612724703400">"Les utilisateurs disposent de leurs propres applis et de leur propre contenu."</string>
+ <string name="user_add_profile_item_summary" msgid="5418602404308968028">"Vous pouvez limiter l\'accès aux applis et au contenu depuis votre compte."</string>
<string name="user_add_user_item_title" msgid="2394272381086965029">"Utilisateur"</string>
<string name="user_add_profile_item_title" msgid="3111051717414643029">"Profil limité"</string>
<string name="user_add_user_title" msgid="5457079143694924885">"Ajouter un utilisateur?"</string>
- <string name="user_add_user_message_long" msgid="1527434966294733380">"Vous pouvez partager cet appareil avec d\'autres personnes en ajoutant des utilisateurs. Chaque utilisateur dispose de son propre espace, où il peut personnaliser, entre autres, ses applications et son fond d\'écran. Chacun peut également modifier les paramètres de l\'appareil, comme les réseaux Wi-Fi, qui touchent tous les utilisateurs.\n\nLorsque vous ajoutez un utilisateur, celui-ci doit configurer son propre espace.\n\nTout utilisateur peut mettre à jour les applications pour les autres utilisateurs. Il se peut que les paramètres et les services d\'accessibilité ne soient pas transférés aux nouveaux utilisateurs."</string>
- <string name="user_add_user_message_short" msgid="3295959985795716166">"Lorsque vous ajoutez un utilisateur, celui-ci doit configurer son espace.\n\nTout utilisateur peut mettre à jour les applications pour tous les autres utilisateurs."</string>
+ <string name="user_add_user_message_long" msgid="1527434966294733380">"Vous pouvez partager cet appareil avec d\'autres personnes en ajoutant des utilisateurs. Chaque utilisateur dispose de son propre espace, où il peut personnaliser, entre autres, ses applis et son fond d\'écran. Chacun peut également modifier les paramètres de l\'appareil, comme les réseaux Wi-Fi, qui touchent tous les utilisateurs.\n\nLorsque vous ajoutez un utilisateur, celui-ci doit configurer son propre espace.\n\nTout utilisateur peut mettre à jour les applis pour les autres utilisateurs. Il se peut que les paramètres et les services d\'accessibilité ne soient pas transférés aux nouveaux utilisateurs."</string>
+ <string name="user_add_user_message_short" msgid="3295959985795716166">"Lorsque vous ajoutez un utilisateur, celui-ci doit configurer son espace.\n\nTout utilisateur peut mettre à jour les applis pour tous les autres utilisateurs."</string>
<string name="user_grant_admin_title" msgid="5157031020083343984">"Définir cet utilisateur comme administrateur?"</string>
- <string name="user_grant_admin_message" msgid="1673791931033486709">"Les administrateurs ont des privilèges spéciaux que les autres utilisateurs n\'ont pas. Un administrateur peut gérer tous les utilisateurs, mettre à jour ou réinitialiser cet appareil, modifier les paramètres, voir toutes les applications installées et accorder ou révoquer les privilèges d\'administrateur à d\'autres personnes."</string>
+ <string name="user_grant_admin_message" msgid="1673791931033486709">"Les administrateurs ont des privilèges spéciaux que les autres utilisateurs n\'ont pas. Un administrateur peut gérer tous les utilisateurs, mettre à jour ou réinitialiser cet appareil, modifier les paramètres, voir toutes les applis installées et accorder ou révoquer les privilèges d\'administrateur à d\'autres personnes."</string>
<string name="user_grant_admin_button" msgid="5441486731331725756">"Définir comme administrateur"</string>
<string name="user_setup_dialog_title" msgid="8037342066381939995">"Configurer l\'utilisateur?"</string>
<string name="user_setup_dialog_message" msgid="269931619868102841">"Assurez-vous que la personne est disponible et qu\'elle peut utiliser l\'appareil pour configurer son espace."</string>
@@ -644,7 +644,7 @@
<string name="user_new_profile_name" msgid="2405500423304678841">"Nouveau profil"</string>
<string name="user_info_settings_title" msgid="6351390762733279907">"Informations sur l\'utilisateur"</string>
<string name="profile_info_settings_title" msgid="105699672534365099">"Informations de profil"</string>
- <string name="user_need_lock_message" msgid="4311424336209509301">"Avant de créer un profil limité, vous devez définir un écran de verrouillage pour protéger vos applications et vos données personnelles."</string>
+ <string name="user_need_lock_message" msgid="4311424336209509301">"Avant de créer un profil limité, vous devez définir un écran de verrouillage pour protéger vos applis et vos données personnelles."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Définir verrouillage écran"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Passer à <xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Création d\'un utilisateur en cours…"</string>
@@ -663,9 +663,9 @@
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Retirer"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Réinitialisation de la session Invité en cours…"</string>
<string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Réinitialiser la session d\'invité?"</string>
- <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Une nouvelle session d\'invité sera lancée, et toutes les applications et données de la session en cours seront supprimées"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Une nouvelle session d\'invité sera lancée, et toutes les applis et données de la session en cours seront supprimées"</string>
<string name="guest_exit_dialog_title" msgid="1846494656849381804">"Quitter le mode Invité?"</string>
- <string name="guest_exit_dialog_message" msgid="1743218864242719783">"Les applications et les données de la session d\'invité en cours seront supprimées"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"Les applis et les données de la session d\'invité en cours seront supprimées"</string>
<string name="grant_admin" msgid="4323199171790522574">"Oui, le définir comme administrateur"</string>
<string name="not_grant_admin" msgid="3557849576157702485">"Non, ne pas le définir comme administrateur"</string>
<string name="guest_exit_dialog_button" msgid="1736401897067442044">"Quitter"</string>
@@ -724,14 +724,14 @@
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"Par défaut"</string>
<string name="turn_screen_on_title" msgid="2662312432042116026">"Commande d\'activation de l\'écran"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Autoriser l\'activation de l\'écran"</string>
- <string name="allow_turn_screen_on_description" msgid="43834403291575164">"Autorisez une application à activer l\'écran. Lorsque vous accordez cette autorisation, l\'application peut activer l\'écran à tout moment sans que vous lui demandiez."</string>
+ <string name="allow_turn_screen_on_description" msgid="43834403291575164">"Autorisez une appli à activer l\'écran. Lorsque vous accordez cette autorisation, l\'appli peut activer l\'écran à tout moment sans que vous lui demandiez."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"Arrêter la diffusion de <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"Si vous diffusez <xliff:g id="SWITCHAPP">%1$s</xliff:g> ou changez la sortie, votre diffusion actuelle s\'arrêtera"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"Diffuser <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Changer la sortie"</string>
<string name="back_navigation_animation" msgid="8105467568421689484">"Animations pour le retour prédictif"</string>
<string name="back_navigation_animation_summary" msgid="741292224121599456">"Activer les animations système pour le retour prédictif."</string>
- <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"Ce paramètre permet d\'activer les animations du système pour l\'animation des gestes prédictifs. Cela exige de définir le paramètre enableOnBackInvokedCallback à Vrai pour chaque application dans le fichier de configuration."</string>
+ <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"Ce paramètre permet d\'activer les animations du système pour l\'animation des gestes prédictifs. Cela exige de définir le paramètre enableOnBackInvokedCallback à Vrai pour chaque appli dans le fichier de configuration."</string>
<string name="font_scale_percentage" msgid="2624057443622817886">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string>
<string name="not_specified" msgid="5423502443185110328">"Non précisé"</string>
<string name="neuter" msgid="2075249330106127310">"Neutre"</string>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index 300dca1ea255..51b0bf0d7165 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Autoriser l\'enregistrement de toute application sur un espace de stockage externe, indépendamment des valeurs du fichier manifeste"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Forcer le redimensionnement des activités"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Rendre toutes les activités redimensionnables pour le mode multifenêtre, indépendamment des valeurs du fichier manifeste"</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"Activer les fenêtres de forme libre"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Activer la compatibilité avec les fenêtres de forme libre expérimentales"</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"Activer les anciennes fenêtres de forme libre"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"Permet d\'activer la compatibilité avec les anciennes fenêtres de forme libre expérimentales."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Mot de passe de sauvegarde ordi"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Les sauvegardes complètes sur ordi ne sont actuellement pas protégées"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Appuyez pour modifier ou supprimer le mot de passe des sauvegardes complètes sur ordi."</string>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index d00d6d3a5fd8..4f82af38aab7 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Permite que calquera aplicación compatible se poida escribir nun almacenamento externo, independentemente dos valores do manifesto"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Forzar o axuste do tamaño das actividades"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Permite axustar o tamaño de todas as actividades para o modo multiventá, independentemente dos valores do manifesto"</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"Activar ventás de forma libre"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Activa a compatibilidade con ventás de forma libre experimentais"</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"Activar ventás de forma libre (antigas)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"Activa a compatibilidade coas ventás de forma libre experimentais antigas."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Contrasinal para copias"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"As copias de seguranza de ordenador completas non están protexidas"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Toca para cambiar ou quitar o contrasinal para as copias de seguranza completas de ordenador"</string>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index 0c204f7b9b69..9ea6f4609a81 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"મેનિફેસ્ટ મૂલ્યોને ધ્યાનમાં લીધા સિવાય, કોઈપણ ઍપને બાહ્ય સ્ટોરેજ પર લખાવા માટે લાયક બનાવે છે"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"પ્રવૃત્તિઓને ફરીથી કદ યોગ્ય થવા માટે ફરજ પાડો"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"મૅનિફેસ્ટ મૂલ્યોને ધ્યાનમાં લીધા સિવાય, તમામ પ્રવૃત્તિઓને મલ્ટી-વિન્ડો માટે ફરીથી કદ બદલી શકે તેવી બનાવો."</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"ફ્રીફોર્મ વિન્ડો ચાલુ કરો"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"પ્રાયોગિક ફ્રીફોર્મ વિન્ડો માટે સપોર્ટને ચાલુ કરો."</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"ફ્રીફોર્મ વિન્ડો ચાલુ કરો (જૂની)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"પ્રાયોગિક જૂની ફ્રીફોર્મ વિન્ડો માટે સપોર્ટ મેળવવાની સુવિધા ચાલુ કરો."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"ડેસ્કટૉપ બૅકઅપ પાસવર્ડ"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"ડેસ્કટૉપ સંપૂર્ણ બૅકઅપ હાલમાં સુરક્ષિત નથી"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"ડેસ્કટૉપ સંપૂર્ણ બેકઅપ્સ માટેનો પાસવર્ડ બદલવા અથવા દૂર કરવા માટે ટૅચ કરો"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 2c938a610c0b..6a7179f282df 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"इससे कोई भी ऐप्लिकेशन बाहरी स्टोरेज में रखने लायक बन जाता है, चाहे उसकी मेनिफ़ेस्ट वैल्यू कुछ भी हो"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"विंडो के हिसाब से गतिविधियों का साइज़ बदल दें"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"सभी गतिविधियों को मल्टी-विंडो (एक से ज़्यादा ऐप्लिकेशन, एक साथ) के लिए साइज़ बदलने लायक बनाएं, चाहे उनकी मेनिफ़ेस्ट वैल्यू कुछ भी हो."</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"फ़्रीफ़ॉर्म विंडो (एक साथ कई विंडो दिखाना) चालू करें"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"फ़्रीफ़ॉर्म विंडो आज़माने की सुविधा चालू करें."</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"फ़्रीफ़ॉर्म विंडो वाला लेगसी मोड चालू करें"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"एक्सपेरिमेंट के तौर पर उपलब्ध फ़्रीफ़ॉर्म विंडो वाला लेगसी मोड चालू करें."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"डेस्‍कटॉप बैकअप पासवर्ड"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"डेस्‍कटॉप का पूरा बैकअप फ़िलहाल सुरक्षित नहीं है"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"डेस्कटॉप के पूरे बैक अप का पासवर्ड बदलने या हटाने के लिए टैप करें"</string>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index 260e9c2f7b43..9f88c226a6bb 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Aplikacije se mogu zapisivati u vanjsku pohranu neovisno o vrijednostima manifesta"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Nametni mogućnost promjene veličine za aktivnosti"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Omogući mijenjanje veličine svih aktivnosti za više prozora, neovisno o vrijednostima manifesta."</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"Omogući prozore slobodnog oblika"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Omogućuje podršku za eksperimentalne prozore slobodnog oblika."</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"Omogući prozore slobodnog oblika (naslijeđeno)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"Omogući podršku za eksperimentalne naslijeđene prozore slobodnog oblika."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Zaporka sigurnosne kopije"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Potpune sigurnosne kopije na stolnom računalu trenutačno nisu zaštićene"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Dodirnite da biste promijenili ili uklonili zaporku za potpune sigurnosne kopije na računalu"</string>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index b16f4a3dc2e3..7a8d26f63b69 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Lehetővé teszi bármely alkalmazás külső tárhelyre való írását a jegyzékértékektől függetlenül"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Tevékenységek átméretezésének kényszerítése"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Legyen az összes tevékenység átméretezhető a többablakos megjelenítés érdekében a jegyzékértékektől függetlenül."</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"Szabad formájú ablakok engedélyezése"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Kísérleti, szabad formájú ablakok támogatásának engedélyezése."</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"Szabad formájú ablakok engedélyezése (régi)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"Kísérleti, régi szabad formájú ablakok támogatásának engedélyezése."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Asztali mentés jelszava"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Az asztali teljes biztonsági mentések jelenleg nem védettek."</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Koppintson ide az asztali teljes mentések jelszavának módosításához vagy eltávolításához"</string>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index bd9e564a27af..15ea2723ad20 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Թույլ է տալիս ցանկացած հավելված պահել արտաքին սարքում՝ մանիֆեստի արժեքներից անկախ"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Չափերի փոփոխում բազմապատուհան ռեժիմում"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Բոլոր ակտիվությունների չափերը բազմապատուհան ռեժիմի համար դարձնել փոփոխելի՝ մանիֆեստի արժեքներից անկախ:"</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"Ակտիվացնել կամայական ձևի պատուհանները"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Միացնել ազատ ձևի փորձնական պատուհանների աջակցումը:"</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"Միացնել կամայական ձևի պատուհանները (հնացած)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"Միացնել կամայական ձևի պատուհանների ստեղծման հնացած փորձնական գործառույթի աջակցումը:"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Աշխատասեղանի պահուստավորման գաղտնաբառ"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Աշխատասեղանի ամբողջական պահուստավորումները այժմ պաշտպանված չեն"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Հպեք՝ աշխատասեղանի ամբողջական պահուստավորման գաղտնաբառը փոխելու կամ հեռացնելու համար"</string>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index b3a1291d0fb0..2c36cf167272 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Membuat semua aplikasi dapat ditulis ke penyimpanan eksternal, terlepas dari nilai manifes"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Paksa aktivitas agar ukurannya dapat diubah"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Membuat semua aktivitas dapat diubah ukurannya untuk banyak jendela, terlepas dari nilai manifes."</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"Aktifkan jendela berformat bebas"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Aktifkan dukungan untuk jendela eksperimental berformat bebas."</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"Aktifkan jendela freeform (versi lama)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"Aktifkan dukungan untuk jendela freeform eksperimental versi lama."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Sandi cadangan desktop"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Saat ini cadangan desktop penuh tidak dilindungi"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Ketuk guna mengubah atau menghapus sandi untuk cadangan lengkap desktop"</string>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index 7712b8aed985..793663a5f060 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Gerir öll forrit skrifanleg í ytra geymslurými, óháð gildum í upplýsingaskrá"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Þvinga breytanlega stærð virkni"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Gera stærð allrar virkni breytanlega svo að hún henti fyrir marga glugga, óháð gildum í upplýsingaskrá."</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"Virkja glugga með frjálsu sniði"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Virkja stuðning við glugga með frjálsu sniði á tilraunastigi."</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"Virkja glugga á frjálsu sniði (eldra)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"Virkja stuðning við eldri tilraunaglugga á frjálsu sniði."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Aðgangsorð tölvuafritunar"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Heildarafritun á tölvu er ekki varin sem stendur."</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Ýttu til að breyta eða fjarlægja aðgangsorðið fyrir heildarafritun á tölvu"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index a661700e009d..e88977eb5f9c 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Consente l\'installazione di qualsiasi app su memoria esterna, indipendentemente dai valori manifest"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Imponi formato modificabile alle attività"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Rendi il formato di tutte le attività modificabile per la modalità multi-finestra, indipendentemente dai valori manifest"</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"Attiva finestre a forma libera"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Attiva il supporto delle finestre a forma libera sperimentali"</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"Attiva finestre a forma libera (legacy)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"Attiva il supporto delle finestre a forma libera sperimentali legacy."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Password di backup desktop"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"I backup desktop completi non sono attualmente protetti"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Tocca per modificare o rimuovere la password per i backup desktop completi"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index fe674bcab81a..8b08e4f4e03a 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"מאפשר כתיבה של כל אפליקציה באחסון חיצוני, ללא התחשבות בערכי המניפסט"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"אילוץ יכולת קביעת גודל של הפעילויות"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"מאפשר יכולת קביעת גודל של כל הפעילויות לריבוי חלונות, ללא התחשבות בערכי המניפסט."</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"הפעלת האפשרות לשנות את הגודל והמיקום של החלונות"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"הפעלת תמיכה בתכונה הניסיונית של שינוי הגודל והמיקום של החלונות."</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"הפעלת שינוי הגודל והמיקום של החלונות (מדור קודם)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"הפעלת תמיכה בתכונה הניסיונית מדור קודם של שינוי הגודל והמיקום של החלונות."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"סיסמת גיבוי שולחן העבודה"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"גיבויים מלאים בשולחן העבודה אינם מוגנים כעת"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"יש להקיש כדי לשנות או להסיר את הסיסמה לגיבויים מלאים בשולחן העבודה"</string>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index f5ee5c4357c6..6cd7505f6383 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"マニフェストの値に関係なく、すべてのアプリを外部ストレージに書き込めるようになります"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"アクティビティをサイズ変更可能にする"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"マニフェストの値に関係なく、マルチウィンドウですべてのアクティビティのサイズを変更できるようにします。"</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"フリーフォーム ウィンドウを有効にする"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"試験運用機能のフリーフォーム ウィンドウのサポートを有効にします。"</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"フリーフォーム ウィンドウを有効にする(従来版)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"従来の試験運用版のフリーフォーム ウィンドウのサポートを有効にします。"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"PC バックアップ パスワード"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"デスクトップのフルバックアップは現在保護されていません"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"デスクトップのフルバックアップ用のパスワードを変更または削除する場合にタップします"</string>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index 1c5822c466e8..4da0f5f461dd 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -440,8 +440,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"აპები ჩაიწერება გარე მეხსიერებაზე აღწერის ფაილების მნიშვნელობების მიუხედავად"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"ზომაცვლადი აქტივობების იძულება"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"მანიფესტის მნიშვნელობების მიუხედავად, მრავალი ფანჯრის რეჟიმისთვის ყველა აქტივობის ზომაცვლადად გადაქცევა."</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"თავისუფალი ფორმის მქონე ფანჯრების ჩართვა"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"თავისუფალი ფორმის მქონე ფანჯრების მხარდაჭერის ექსპერიმენტული ფუნქციის ჩართვა."</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"თავისუფალი ფორმის ფანჯრების ჩართვა (მოძველებული)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"თავისუფალი ფორმის ექსპერიმენტული მოძველებული ფანჯრების ჩართვა."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"დესკტოპის სარეზერვო ასლის პაროლი"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"დესკტოპის სრული სარეზერვო ასლები ამჟამად დაცული არ არის"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"შეეხეთ დესკტოპის სრული სარეზერვო ასლების პაროლის შესაცვლელად ან წასაშლელად"</string>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index ef9b0050fa65..07f34e2df6d0 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Манифест мәндеріне қарамастан, кез келген қолданбаны сыртқы жадқа жазуға рұқсат беру"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Әрекеттердің өлшемін өзгертуге рұқсат ету"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Манифест мәндеріне қарамастан, бірнеше терезе режимінде барлық әрекеттердің өлшемін өзгертуге рұқсат беру"</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"Еркін пішінді терезелерге рұқсат беру"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Еркін пішінді терезелерді құру эксперименттік функиясын қосу"</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"Еркін пішінді терезелерге рұқсат беру (бұрынғы)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"Эксперименттік бұрынғы еркін пішінді терезелерді қолдауға рұқсат береді."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Компьютердегі сақтық көшірме құпия сөзі"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Компьютердегі толық сақтық көшірмелер қазір қорғалмаған."</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Үстелдік компьютердің толық сақтық көшірмелерінің кілтсөзін өзгерту немесе жою үшін түртіңіз"</string>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index 199b1141c54a..ff594e3b3e34 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"ធ្វើឲ្យកម្មវិធីទាំងឡាយមានសិទ្ធិសរសេរទៅកាន់ឧបករណ៍ផ្ទុកខាងក្រៅ ដោយមិនគិតពីតម្លៃមេនីហ្វេសថ៍"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"បង្ខំឲ្យសកម្មភាពអាចប្តូរទំហំបាន"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"ធ្វើឲ្យសកម្មភាពទាំងអស់អាចប្តូរទំហំបានសម្រាប់ពហុវិនដូ ដោយមិនគិតពីតម្លៃមេនីហ្វេសថ៍។"</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"បើកដំណើរការផ្ទាំងវិនដូទម្រង់សេរី"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"បើកឱ្យអាចប្រើផ្ទាំងវិនដូទម្រង់សេរីពិសោធន៍។"</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"បើកវិនដូទម្រង់សេរី (ចាស់)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"បើកជំនួយសម្រាប់វិនដូទម្រង់សេរីចាស់ក្នុងដំណាក់កាលពិសោធន៍។"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"ពាក្យ​សម្ងាត់​បម្រុង​ទុក​លើកុំព្យូទ័រ"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"បច្ចុប្បន្ន ការ​បម្រុង​ទុក​ពេញលេញនៅលើកុំព្យូទ័រមិន​ត្រូវ​បាន​ការពារ​ទេ"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"ប៉ះដើម្បីប្ដូរ ឬយកពាក្យសម្ងាត់ចេញសម្រាប់ការបម្រុងទុកពេញលេញលើកុំព្យូទ័រ"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index 6ff80d80279d..afea19ffbdc2 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"ಮ್ಯಾನಿಫೆಸ್ಟ್ ಮೌಲ್ಯಗಳು ಯಾವುದೇ ಆಗಿದ್ದರೂ, ಬಾಹ್ಯ ಸಂಗ್ರಹಣೆಗೆ ಬರೆಯಲು ಯಾವುದೇ ಅಪ್ಲಿಕೇಶನ್‌ ಅನ್ನು ಅರ್ಹಗೊಳಿಸುತ್ತದೆ"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"ಚಟುವಟಿಕೆಗಳನ್ನು ಮರುಗಾತ್ರಗೊಳಿಸುವಂತೆ ಒತ್ತಾಯ ಮಾಡಿ"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"ಮ್ಯಾನಿಫೆಸ್ಟ್ ಮೌಲ್ಯಗಳನ್ನು ಪರಿಗಣಿಸದೇ, ಬಹು-ವಿಂಡೊಗೆ ಎಲ್ಲಾ ಚಟುವಟಿಕೆಗಳನ್ನು ಮರುಗಾತ್ರಗೊಳಿಸುವಂತೆ ಮಾಡಿ."</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"ಮುಕ್ತಸ್ವರೂಪದ ವಿಂಡೊಗಳನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"ಪ್ರಾಯೋಗಿಕ ಫ್ರೀಫಾರ್ಮ್ ವಿಂಡೊಗಳಿಗೆ ಬೆಂಬಲವನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ."</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"ಫ್ರೀಫಾರ್ಮ್ ವಿಂಡೋಗಳನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ (ಲೆಗಸಿ)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"ಪ್ರಾಯೋಗಿಕ ಲೆಗಸಿ ಫ್ರೀಫಾರ್ಮ್ ವಿಂಡೋಗಳಿಗೆ ಬೆಂಬಲವನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"ಡೆಸ್ಕ್‌ಟಾಪ್ ಬ್ಯಾಕಪ್ ಪಾಸ್‌ವರ್ಡ್"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"ಡೆಸ್ಕ್‌ಟಾಪ್‌‌ ಪೂರ್ಣ ಬ್ಯಾಕಪ್‌‌ಗಳನ್ನು ಪ್ರಸ್ತುತ ರಕ್ಷಿಸಲಾಗಿಲ್ಲ"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"ಡೆಸ್ಕ್‌ಟಾಪ್‌ನ ಪೂರ್ಣ ಬ್ಯಾಕಪ್‌ಗಳಿಗೆ ಪಾಸ್‌ವರ್ಡ್‌ ಬದಲಾಯಿಸಲು ಅಥವಾ ತೆಗೆದುಹಾಕಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index af5f9d4c5230..e88fc0434655 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"매니페스트 값과 관계없이 모든 앱이 외부 저장소에 작성되도록 허용"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"활동의 크기가 조정 가능하도록 설정"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"모든 활동을 매니페스트 값에 관계없이 멀티 윈도우용으로 크기 조정 가능하도록 설정"</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"자유 형식 창 사용"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"자유 형식 창 지원 사용"</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"자유 형식 창 사용(레거시)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"실험적인 레거시 자유 형식 창에 대한 지원을 사용하도록 설정합니다."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"데스크톱 백업 비밀번호"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"데스크톱 전체 백업에 비밀번호가 설정되어 있지 않음"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"데스크톱 전체 백업에 대한 비밀번호를 변경하거나 삭제하려면 탭하세요."</string>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index 1d3f44ade109..16f2ddbdf3ad 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Манифест маанилерине карабастан бардык колдонмолорду тышкы сактагычка сактоого уруксат берет"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Бир нече терезе режиминде өлчөмдү өзгөртүү"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Бир нече терезе режиминде өлчөмдү өзгөртүүгө уруксат берет (манифесттин маанилерине карабастан)"</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"Эркин формадагы терезелерди түзүүнү иштетүү"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Эркин формадагы терезелерди түзүү боюнча сынамык функциясы иштетилет."</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"Эркин формадагы терезелерди түзүүнү иштетүү (эски)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"Эркин формадагы эски терезелерди түзүү боюнча сынамык функциясы иштетилет."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Камдык көчүрмөнүн сырсөзү"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Толук камдык көчүрмөлөр учурда корголгон эмес"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Иш тактасынын камдалган сырсөзүн өзгөртүү же алып салуу үчүн таптап коюңуз"</string>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index d99759b625b6..1eec5a7b9c8a 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"ເຮັດໃຫ້ທຸກແອັບມີສິດໄດ້ຮັບການຂຽນໃສ່ພື້ນທີ່ຈັດເກັບຂໍ້ມູນພາຍນອກ, ໂດຍບໍ່ຄຳນຶງເຖິງຄ່າ manifest"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"ບັງ​ຄັງ​ໃຫ້​ການ​ເຄື່ອນ​ໄຫວ​ປ່ຽນ​ຂະ​ໜາດ​ໄດ້"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"ເຮັດໃຫ້ທຸກການ​ເຄື່ອນ​ໄຫວສາມາດປັບຂະໜາດໄດ້ສຳລັບຫຼາຍໜ້າຈໍ, ໂດຍບໍ່ຄຳນຶງເຖິງຄ່າ manifest."</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"ເປີດໃຊ້ໜ້າຈໍຮູບແບບອິດສະຫຼະ"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"ເປີດໃຊ້ການຮອງຮັບໜ້າຈໍຮູບແບບອິດສະຫຼະແບບທົດລອງ."</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"ເປີດການນຳໃຊ້ໜ້າຈໍຮູບແບບອິດສະຫຼະ (ແບບເກົ່າ)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"ເປີດການນຳໃຊ້ການຮອງຮັບໜ້າຈໍຮູບແບບອິດສະຫຼະແບບເກົ່າເວີຊັນທົດລອງ."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"ລະຫັດຜ່ານການສຳຮອງຂໍ້ມູນເດັສທັອບ"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"ການ​ສຳຮອງ​ຂໍ້ມູນ​ເຕັມຮູບແບບ​ໃນ​ເດັສທັອບ​ຍັງ​ບໍ່​ໄດ້​ຮັບ​ການ​ປ້ອງກັນ​ໃນ​ເວລາ​ນີ້"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"ແຕະເພື່ອປ່ຽນ ຫຼື ລຶບລະຫັດຂອງການສຳຮອງຂໍ້ມູນເຕັມຮູບແບບໃນເດັສທັອບ"</string>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index 204afc72d0e2..d879c9dada9a 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Nustatoma, kad visas programas būtų galima įrašyti į išorinę saugyklą, nepaisant aprašo verčių"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Priv. nust., kad veiksm. b. g. atl. kelių d. lang."</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Nustatyti, kad visus veiksmus būtų galima atlikti kelių dydžių languose, nepaisant aprašo verčių."</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"Įgalinti laisvos formos langus"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Įgalinti eksperimentinių laisvos formos langų palaikymą."</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"Įgalinti laisvos formos langus (pasenę)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"Įgalinti eksperimentinių pasenusių laisvos formos langų palaikymą."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Viet. atsrg. kop. slapt."</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Šiuo metu visos vietinės atsarginės kopijos neapsaugotos"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Jei norite pakeisti ar pašalinti visų stalinio kompiuterio atsarginių kopijų slaptažodį, palieskite"</string>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index 71d11d562a62..ac00d0595295 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Ļauj jebkuru lietotni ierakstīt ārējā krātuvē neatkarīgi no manifesta vērtības."</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Pielāgot darbības"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Pielāgot visas darbības vairāku logu režīmam neatkarīgi no vērtībām manifestā."</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"Iespējot brīvās formas logus"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Iespējot eksperimentālo brīvās formas logu atbalstu."</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"Iespējot brīvās formas logus (mantots režīms)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"Iespējot atbalstu eksperimentālajam, mantotajam brīvās formas logu režīmam."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Datora dublējuma parole"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Darbvirsmas pilnie dublējumi pašlaik nav aizsargāti."</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Pieskarieties, lai mainītu vai noņemtu paroli pilniem datora dublējumiem."</string>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index 537f8b55a330..b9fabe67984a 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Сите апликации ќе бидат подобни за запишување во надворешната меморија, независно од вредностите на манифестот"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Наметни променлива големина на активностите"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Сите активности ќе имаат променлива големина во режимот со повеќе прозорци, независно од вредностите на манифестот."</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"Овозможи прозорци со слободна форма"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Овозможи поддршка за експериментални прозорци со слободна форма."</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"Овозможи прозорци со менлива големина (застарено)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"Овозможете поддршка за експериментални застарени прозорци со менлива големина."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Лозинка за бекап на компјутер"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Целосниот бекап на компјутерот во моментов не е заштитен"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Допрете за да се промени или отстрани лозинката за целосен бекап на компјутерот"</string>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index c096260cf70a..331b0a8894d7 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"മാനിഫെസ്റ്റ് മൂല്യങ്ങൾ പരിഗണിക്കാതെ, ബാഹ്യ സ്റ്റോറേജിലേക്ക് എഴുതപ്പെടുന്നതിന് ഏതൊരു ആപ്പിനെയും യോഗ്യമാക്കുന്നു"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"വലുപ്പം മാറ്റാൻ പ്രവർത്തനങ്ങളെ നിർബന്ധിക്കുക"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"മാനിഫെസ്റ്റ് മൂല്യങ്ങൾ പരിഗണിക്കാതെ, എല്ലാ ആക്ടിവിറ്റികളെയും മൾട്ടി-വിൻഡോയ്ക്കായി വലുപ്പം മാറ്റുക."</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"ഫ്രീഫോം വിൻഡോകൾ പ്രവർത്തനക്ഷമമാക്കുക"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"പരീക്ഷണാത്മക ഫ്രീഫോം വിൻഡോകൾക്കുള്ള പിന്തുണ പ്രവർത്തനക്ഷമമാക്കുക."</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"ഫ്രീഫോം വിൻഡോകൾ പ്രവർത്തനക്ഷമമാക്കുക (ലെഗസി)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"പരീക്ഷണാത്മക ലെഗസി ഫ്രീഫോം വിൻഡോകൾക്കുള്ള പിന്തുണ പ്രവർത്തനക്ഷമമാക്കുക."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"ഡെ‌സ്‌ക്ടോപ്പ് ബാക്കപ്പ് പാസ്‌വേഡ്"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"ഡെസ്‌ക്‌ടോപ്പ് പൂർണ്ണ ബാക്കപ്പുകൾ നിലവിൽ പരിരക്ഷിച്ചിട്ടില്ല"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"ഡെസ്‌ക്‌ടോപ്പ് പൂർണ്ണ ബാക്കപ്പുകൾക്കായി പാസ്‌വേഡുകൾ മാറ്റാനോ നീക്കംചെയ്യാനോ ടാപ്പുചെയ്യുക"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index b3bca99253c0..3c0a5d854c34 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Манифест утгыг нь үл хамааран дурын апп-г гадаад санах ойд бичих боломжтой болгодог"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Үйл ажиллагааны хэмжээг өөрчилж болохуйц болгох"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Тодорхойлогч файлын утгыг үл хамааран, бүх үйл ажиллагааны хэмжээг олон цонхонд өөрчилж болохуйц болгоно уу."</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"Чөлөөт хэлбэрийн цонхыг идэвхжүүлэх"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Туршилтын чөлөөт хэлбэрийн цонхны дэмжлэгийг идэвхжүүлнэ үү."</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"Чөлөөт хэлбэрийн цонхыг идэвхжүүлэх (уламжлалт)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"Туршилтын чөлөөт хэлбэрийн уламжлалт цонхны дэмжлэгийг идэвхжүүлнэ үү."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Компьютерын нөөцлөлтийн нууц үг"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Компьютерын бүрэн нөөцлөлт одоогоор хамгаалалтгүй байна"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Компьютерийн бүтэн нөөцлөлтийн нууц үгийг өөрчлөх, устгах бол дарна уу"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index f6467fa740ad..93613f934d92 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"मॅनिफेस्‍ट मूल्ये काहीही असू देत, कोणत्याही अ‍ॅपला बाह्य स्टोरेजवर राइट करण्यासाठी पात्र बनविते"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"ॲक्टिव्हिटीचा आकार बदलण्यायोग्य होण्याची सक्ती करा"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"मॅनिफेस्‍ट मूल्ये काहीही असू देत, एकाहून अधिक विंडोसाठी सर्व अ‍ॅक्टिव्हिटीचा आकार बदलण्यायोग्य करा."</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"freeform windows सुरू करा"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"प्रायोगिक freeform windows साठी सपोर्ट सुरू करा."</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"फ्रीफॉर्म विंडो सुरू करा (लेगसी)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"प्रायोगिक लेगसी फ्रीफॉर्म विंडोसाठी सपोर्ट सुरू करा."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"डेस्कटॉप बॅकअप पासवर्ड"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"डेस्कटॉप पूर्ण बॅक अप सध्या संरक्षित नाहीत"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"डेस्कटॉपच्या पूर्ण बॅकअपसाठी असलेला पासवर्ड बदलण्यासाठी किंवा काढण्यासाठी टॅप करा"</string>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index 3301b5472673..1a9302544a20 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Menjadikan sebarang apl layak ditulis ke storan luaran, tanpa mengambil kira nilai manifes"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Paksa aktiviti supaya boleh diubah saiz"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Bolehkan semua saiz aktiviti diubah untuk berbilang tetingkap, tanpa mengambil kira nilai manifes."</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"Dayakan tetingkap bentuk bebas"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Dayakan sokongan untuk tetingkap bentuk bebas percubaan."</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"Dayakan tetingkap bentuk bebas (lama)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"Dayakan sokongan untuk tetingkap bentuk bebas lama yang bersifat percubaan."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Kata laluan sandaran desktop"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Sandaran penuh desktop tidak dilindungi pada masa ini"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Ketik untuk menukar atau mengalih keluar kata laluan untuk sandaran penuh desktop"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index 79f1bc3ddd82..548358f7a937 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"သတ်မှတ်တန်ဖိုးများ မည်သို့ပင်ရှိစေ ပြင်ပသိုလှောင်ခန်းများသို့ မည်သည့်အက်ပ်ကိုမဆို ဝင်ရောက်ခွင့်ပြုသည်"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"လုပ်ဆောင်ချက်များ အရွယ်ပြောင်းနိုင်ခြင်း"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"သတ်မှတ်တန်ဖိုး မည်သို့ပင်ရှိစေ ဝင်းဒိုးများ၏ လုပ်ဆောင်မှုအားလုံးကို အရွယ်အစားပြင်သည်။"</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"ပုံစံမျိုးစုံ ဝင်းဒိုးများ ဖွင့်ရန်"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"ပုံစံမျိုးစုံဝင်းဒိုးများ စမ်းသပ်ခြင်းအတွက် ပံ့ပိုးမှုကို ဖွင့်သည်"</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"အလွတ်ပုံစံ ဝင်းဒိုးများ ဖွင့်ပါ (အဟောင်း)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"အလွတ်ပုံစံဝင်းဒိုးအဟောင်းများ စမ်းသပ်ရန် ပံ့ပိုးမှုရယူပါ။"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"ဒက်စ်တော့ အရန်စကားဝှက်"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"ဒက်စ်တော့ တစ်ခုလုံး အရန်သိမ်းဆည်းခြင်းကို လက်ရှိတွင် ကာကွယ်မထားပါ"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"ဒက်စ်တော့ အပြည့်အဝ အရန်သိမ်းခြင်းအတွက် စကားဝှက်ကို ပြောင်းရန် သို့မဟုတ် ဖယ်ရှားရန် တို့ပါ။"</string>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index 23031c37dbf3..691dd3b89b22 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Dette gjør at alle apper kan lagres på eksterne lagringsmedier – uavhengig av manifestverdier"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Alle aktiviteter kan endre størrelse"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Gjør at alle aktiviteter kan endre størrelse for flervindusmodus, uavhengig av manifestverdier."</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"Slå på vinduer i fritt format"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Slå på støtte for vinduer i eksperimentelt fritt format."</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"Slå på vinduer i fritt format (eldre versjon)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"Slå på støtte for eldre versjon av vinduer i eksperimentelt fritt format."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Passord for sikkerhetskopiering på datamaskin"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Fullstendig sikkerhetskopiering på datamaskin er ikke beskyttet"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Trykk for å endre eller fjerne passordet for fullstendige sikkerhetskopier på datamaskinen"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index 38e137d28767..060719459e07 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"तोकिएको नियमको ख्याल नगरी एपलाई बाह्य भण्डारणमा चल्ने बनाउनुहोस्"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"बलपूर्वक एपहरूको आकार मिलाउन मिल्ने बनाउनुहोस्"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"तोकिएको नियमको ख्याल नगरी एपलाई एकभन्दा बढी विन्डोमा रिसाइज गर्न सकिने बनाउनुहोस्।"</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"फ्रिफर्म विन्डोहरू अन गर्नुहोस्"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"प्रयोगात्मक फ्रिफर्म विन्डोहरू चल्ने बनाउनुहोस्"</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"फ्रिफर्म विन्डोहरू अन गर्नुहोस् (लिगेसी)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"प्रयोगात्मक लिगेसी फ्रिफर्म विन्डोहरू चल्ने बनाउनुहोस्"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"डेस्कटप ब्याकअप पासवर्ड"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"हाल डेस्कटपका सबै ब्याकअप पासवर्ड सुरक्षित छैनन्"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"डेस्कटप पूर्ण ब्याकअपको लागि पासवर्ड बदल्न वा हटाउन ट्याप गर्नुहोस्"</string>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index 9e0088f1b1d0..c7047a66333f 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Hiermee komt elke app in aanmerking voor schrijven naar externe opslag, ongeacht de manifestwaarden"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Formaat activiteiten geforceerd aanpasbaar maken"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Maak het formaat van alle activiteiten aanpasbaar, ongeacht de manifestwaarden"</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"Vensters met vrije vorm aanzetten"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Zet ondersteuning voor vensters met experimentele vrije vorm aan"</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"Vensters met vrije vorm aanzetten (verouderd)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"Zet ondersteuning voor verouderde vensters met experimentele vrije vorm aan."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Wachtwoord desktopback-up"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Volledige back-ups naar desktops zijn momenteel niet beveiligd"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Tik om het wachtwoord voor volledige back-ups naar desktops te wijzigen of te verwijderen"</string>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index 8d4e5cc8cf8f..54ad13ea7214 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"ଯେକୌଣସି ଆପ୍‌କୁ ଏକ୍ସଟର୍ନଲ୍ ଷ୍ଟୋରେଜ୍‌ରେ ଲେଖାଯୋଗ୍ୟ କରନ୍ତୁ, ମେନିଫେଷ୍ଟ ମୂଲ୍ୟ ଯାହା ହୋଇଥାଉ ନା କାହିଁକି"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"ୱିଣ୍ଡୋ ହିସାବରେ କାର୍ଯ୍ୟକଳାପର ଆକାର ବଦଳାନ୍ତୁ"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"ମାନିଫେଷ୍ଟ ମୂଲ୍ୟ ଯାହା ହୋଇଥାଉ ନା କାହିଁକି, ଏକାଧିକ-ୱିଣ୍ଡୋ ପାଇଁ ସମସ୍ତ କାର୍ଯ୍ୟକଳାପକୁ ରିସାଇଜ କରନ୍ତୁ।"</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"ଫ୍ରିଫର୍ମ ୱିଣ୍ଡୋକୁ ସକ୍ଷମ କରନ୍ତୁ"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"ପରୀକ୍ଷାମୂଳକ ଫ୍ରିଫର୍ମ ୱିଣ୍ଡୋଗୁଡ଼ିକ ପାଇଁ ସପୋର୍ଟକୁ ସକ୍ଷମ କରନ୍ତୁ।"</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"ଫ୍ରିଫର୍ମ ୱିଣ୍ଡୋ ସକ୍ଷମ କରନ୍ତୁ (ଲିଗାସି)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"ପରୀକ୍ଷାମୂଳକ ଲିଗାସି ଫ୍ରିଫର୍ମ ୱିଣ୍ଡୋ ପାଇଁ ସପୋର୍ଟ ସକ୍ଷମ କରନ୍ତୁ।"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"ଡେସ୍କଟପ ବେକଅପ ପାସୱାର୍ଡ"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"ଡେସ୍କଟପ୍‌ର ସମ୍ପୂର୍ଣ୍ଣ ବ୍ୟାକଅପ୍‌ଗୁଡ଼ିକ ବର୍ତ୍ତମାନ ସୁରକ୍ଷିତ ନୁହେଁ"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"ଡେସ୍କଟପ୍‌ର ସମ୍ପୂର୍ଣ୍ଣ ବ୍ୟାକ୍‌ଅପ୍‌ ପାଇଁ ପାସ୍‌ୱର୍ଡ ବଦଳାଇବା କିମ୍ୱା କାଢ଼ିଦେବା ନିମନ୍ତେ ଟାପ୍‌ କରନ୍ତୁ"</string>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index 54c9b54c8de2..80d9081629e4 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"ਮੈਨੀਫੈਸਟ ਮੁੱਲਾਂ ਦੀ ਪਰਵਾਹ ਕੀਤੇ ਬਿਨਾਂ, ਕਿਸੇ ਵੀ ਐਪ ਨੂੰ ਬਾਹਰੀ ਸਟੋਰੇਜ \'ਤੇ ਲਿਖਣ ਦੇ ਯੋਗ ਬਣਾਉਂਦੀ ਹੈ"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"ਸਰਗਰਮੀਆਂ ਨੂੰ ਜ਼ਬਰਦਸਤੀ ਆਕਾਰ ਬਦਲਣਯੋਗ ਬਣਾਓ"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"ਮੈਨੀਫ਼ੈਸਟ ਮੁੱਲਾਂ ਦੀ ਪਰਵਾਹ ਕੀਤੇ ਬਿਨਾਂ, ਮਲਟੀ-ਵਿੰਡੋ ਲਈ ਸਾਰੀਆਂ ਸਰਗਰਮੀਆਂ ਨੂੰ ਆਕਾਰ ਬਦਲਣਯੋਗ ਬਣਾਓ।"</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"ਫ੍ਰੀਫਾਰਮ ਵਿੰਡੋਜ਼ ਨੂੰ ਚਾਲੂ ਕਰੋ"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"ਪ੍ਰਯੋਗਮਈ ਫ੍ਰੀਫਾਰਮ ਵਿੰਡੋਜ਼ ਲਈ ਸਮਰਥਨ ਨੂੰ ਚਾਲੂ ਕਰੋ।"</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"ਫ੍ਰੀਫਾਰਮ ਵਿੰਡੋਆਂ ਚਾਲੂ ਕਰੋ (ਵਿਰਾਸਤੀ)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"ਪ੍ਰਯੋਗਮਈ ਵਿਰਾਸਤੀ ਫ੍ਰੀਫਾਰਮ ਵਿੰਡੋਆਂ ਲਈ ਸਹਾਇਤਾ ਚਾਲੂ ਕਰੋ।"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"ਡੈਸਕਟਾਪ ਬੈਕਅੱਪ ਪਾਸਵਰਡ"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"ਡੈਸਕਟਾਪ ਦੇ ਪੂਰੇ ਬੈਕਅੱਪ ਇਸ ਵੇਲੇ ਸੁਰੱਖਿਅਤ ਨਹੀਂ ਹਨ"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"ਡੈਸਕਟਾਪ ਦੇ ਮੁਕੰਮਲ ਬੈਕਅੱਪਾਂ ਲਈ ਪਾਸਵਰਡ ਨੂੰ ਬਦਲਣ ਜਾਂ ਹਟਾਉਣ ਲਈ ਟੈਪ ਕਰੋ"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index ef096876e802..e816e9dc78d8 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Pozwala na zapis aplikacji w pamięci zewnętrznej niezależnie od wartości w pliku manifestu"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Wymuś zmianę rozmiaru okien aktywności"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Zezwalaj na zmianę rozmiaru wszystkich okien aktywności w trybie wielu okien niezależnie od ustawień w pliku manifestu"</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"Włącz dowolny rozmiar okien"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Włącz obsługę eksperymentalnej funkcji dowolnego rozmiaru okien"</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"Włącz dowolny rozmiar okien (starsza wersja)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"Włącz obsługę eksperymentalnej funkcji dowolnego rozmiaru okien w starszej wersji"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Hasło kopii zapasowej"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Pełne kopie zapasowe na komputerze nie są obecnie chronione"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Dotknij, by zmienić lub usunąć hasło pełnych kopii zapasowych na komputerze."</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index e441f058f3e1..db8aac9a88ee 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Qualificar apps para gravação em armazenamento externo, independentemente dos valores do manifesto"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Forçar atividades a serem redimensionáveis"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Tornar todas as atividades redimensionáveis para várias janelas, independentemente dos valores do manifesto"</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"Ativar janelas de forma livre"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Ativar a compatibilidade com janelas experimentais de forma livre"</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"Ativar janelas de forma livre (legado)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"Ativar a compatibilidade com janelas experimentais legadas de forma livre."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Senha de backup local"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Os backups completos não estão protegidos no momento"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Toque para alterar ou remover a senha de backups completos do desktop"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index 7aed3f4ad709..3f253c7a9424 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Torna qualquer aplicação elegível para ser gravada no armazenamento externo, independentemente dos valores do manifesto"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Forçar as atividades a serem redimensionáveis"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Tornar todas as atividades redimensionáveis para várias janelas, independentemente dos valores do manifesto."</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"Ativar janelas de forma livre"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Ativar a compatibilidade com janelas de forma livre experimentais."</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"Ativar janelas de forma livre (antigo)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"Ativar compatibilidade com janelas de forma livre antigas experimentais."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Palavra-passe cópia do computador"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"As cópias de segurança completas no ambiente de trabalho não estão atualmente protegidas"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Tocar para alterar ou remover a palavra-passe para cópias de segurança completas no ambiente de trabalho"</string>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index e441f058f3e1..db8aac9a88ee 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Qualificar apps para gravação em armazenamento externo, independentemente dos valores do manifesto"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Forçar atividades a serem redimensionáveis"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Tornar todas as atividades redimensionáveis para várias janelas, independentemente dos valores do manifesto"</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"Ativar janelas de forma livre"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Ativar a compatibilidade com janelas experimentais de forma livre"</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"Ativar janelas de forma livre (legado)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"Ativar a compatibilidade com janelas experimentais legadas de forma livre."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Senha de backup local"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Os backups completos não estão protegidos no momento"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Toque para alterar ou remover a senha de backups completos do desktop"</string>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index 9a79bdf5be2d..726e264494d6 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Permite scrierea oricărei aplicații eligibile în stocarea externă, indiferent de valorile manifestului"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Forțează redimensionarea activităților"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Permite redimensionarea tuturor activităților pentru modul cu ferestre multiple, indiferent de valorile manifestului."</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"Activează ferestrele cu formă liberă"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Activează compatibilitatea pentru ferestrele experimentale cu formă liberă."</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"Activează ferestrele cu formă liberă (vechi)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"Activează compatibilitatea pentru ferestrele experimentale vechi cu formă liberă."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Parolă backup computer"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"În prezent, backupurile complete pe computer nu sunt protejate"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Atinge ca să modifici sau să elimini parola pentru backupurile complete pe desktop"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index b768cd969c64..f412fed1a072 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Разрешить сохранение приложений на внешних накопителях (независимо от значений в манифесте)"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Изменение размера в многооконном режиме"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Разрешить изменение размера окон в многооконном режиме (независимо от значений в манифесте)"</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"Разрешить создание окон произвольной формы"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Включить экспериментальную функцию создания окон произвольной формы"</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"Разрешить окна произвольной формы (устаревшее)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"Включить устаревшую экспериментальную функцию для создания окон произвольной формы"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Пароль для резервного копирования"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Полные локальные резервные копии в настоящее время не защищены"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Нажмите, чтобы изменить или удалить пароль для резервного копирования"</string>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index e6095e80a13b..9e28d7cafc99 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"මැනිෆෙස්ට් අගයන් නොසලකා, ඕනෑම යෙදුමක් බාහිර ගබඩාවට ලිවීමට සුදුසුකම් ලබා දෙයි"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"ක්‍රියාකාරකම් ප්‍රතිප්‍රමාණ කළ හැකි බවට බල කරන්න"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"මැනිෆෙස්ට් අගයන් නොසලකා, සියලු ක්‍රියාකාරකම් බහු-කවුළුව සඳහා ප්‍රතිප්‍රමාණ කළ හැකි බවට පත් කරන්න."</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"අනියම් හැඩැති කවුළු සබල කරන්න"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"පරීක්ෂණාත්මක අනියම් හැඩැති කවුළු සඳහා සහාය සබල කරන්න."</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"නිදහස් ආකෘති කවුළු සබල කරන්න (ලෙගසිය)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"පරීක්ෂණාත්මක ලෙගසි නිදහස් ආකෘති කවුළු සඳහා සහාය සබල කරන්න."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"ඩෙස්ක්ටොප් උපස්ථ මුරපදය"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"ඩෙස්ක්ටොප් සම්පූර්ණ උපස්ථ දැනට ආරක්ෂා කර නොමැත"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"ඩෙස්ක්ටොප් සම්පූර්ණ උපස්ථ සඳහා මුරපදය වෙනස් කිරීමට හෝ ඉවත් කිරීමට තට්ටු කරන්න"</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index 317336239b53..97bf279fadef 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Umožniť zapísať akúkoľvek aplikáciu do externého úložiska bez ohľadu na hodnoty v manifeste"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Vynútiť možnosť zmeny veľkosti aktivít"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Umožniť zmeniť veľkosť všetkých aktivít na niekoľko okien (bez ohľadu na hodnoty manifestu)"</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"Povoliť okná s voľným tvarom"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Povoliť podporu pre experimentálne okná s voľným tvarom"</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"Povolenie meniteľných okien (starých)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"Povoľte podporu pre experimentálne staré meniteľné okná."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Heslo pre zálohy v počítači"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Úplné zálohy v počítači nie sú momentálne chránené"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Klepnutím zmeníte alebo odstránite heslo pre úplné zálohy do počítača"</string>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index 7ce5d465a3d1..67aeace593db 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Poskrbi, da je ne glede na vrednosti v manifestu mogoče vsako aplikacijo zapisati v zunanjo shrambo."</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Vsili spremembo velikosti za aktivnosti"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Poskrbi, da je ne glede na vrednosti v manifestu mogoče vsem aktivnostim spremeniti velikost za način z več okni."</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"Omogoči okna svobodne oblike"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Omogoči podporo za poskusna okna svobodne oblike."</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"Omogoči okna svobodne oblike (starejše)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"Omogoči podporo za poskusna okna svobodne oblike starejše različice."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Geslo za varnostno kopijo namizja"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Popolne varnostne kopije namizja trenutno niso zaščitene."</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Dotaknite se, če želite spremeniti ali odstraniti geslo za popolno varnostno kopiranje namizja"</string>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index 313fbc2a2c0d..4aa6a8d8519c 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -436,8 +436,10 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Bën që çdo aplikacion të jetë i përshtatshëm për t\'u shkruar në hapësirën ruajtëse të jashtme, pavarësisht nga vlerat e manifestit"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Detyro madhësinë e ndryshueshme për aktivitetet"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Bëj që të gjitha aktivitetet të kenë madhësi të ndryshueshme për përdorimin me shumë dritare, pavarësisht vlerave të manifestit."</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"Aktivizo dritaret me formë të lirë"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Aktivizo mbështetjen për dritaret eksperimentale me formë të lirë."</string>
+ <!-- no translation found for enable_freeform_support (8409932201445109106) -->
+ <skip />
+ <!-- no translation found for enable_freeform_support_summary (2242481082356957934) -->
+ <skip />
<string name="local_backup_password_title" msgid="4631017948933578709">"Fjalëkalimi i rezervimit të desktopit"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Rezervimet e plota të desktopit nuk janë të mbrojtura aktualisht"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Trokit për të ndryshuar ose hequr fjalëkalimin për rezervime të plota të desktopit"</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 217da2c56417..a67c71a89f85 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Омогућава уписивање свих апликација у спољну меморију, без обзира на вредности манифеста"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Принудно омогући промену величине активности"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Омогућава промену величине свих активности за режим са више прозора, без обзира на вредности манифеста."</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"Омогући прозоре произвољног формата"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Омогућава подршку за експерименталне прозоре произвољног формата."</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"Омогући прозоре произвољног формата (застарело)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"Омогућава подршку за застареле експерименталне прозоре произвољног формата."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Лозинка резервне копије за рачунар"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Резервне копије читавог система тренутно нису заштићене"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Додирните да бисте променили или уклонили лозинку за прављење резервних копија читавог система на рачунару"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 38faa8cde5ba..7add088f52d3 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Allar appar kan skrivas till extern lagring, oavsett manifestvärden"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Framtvinga storleksanpassning för aktiviteter"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Gör det möjligt att ändra storleken på alla aktiviteter i flerfönsterläge, oavsett manifestvärden."</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"Aktivera frihandsfönster"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Aktivera stöd för experimentella frihandsfönster."</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"Aktivera frihandsfönster (äldre)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"Aktivera stöd för äldre experimentella frihandsfönster."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Lösenord för säkerhetskopia av datorn"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"De fullständiga säkerhetskopiorna av datorn är för närvarande inte skyddade"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Tryck om du vill ändra eller ta bort lösenordet för fullständig säkerhetskopiering av datorn"</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index 744a79e8f4f4..818db3f76149 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Huruhusu programu yoyote iwekwe kwenye hifadhi ya nje, bila kujali thamani za faili ya maelezo"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Lazimisha shughuli ziweze kubadilishwa ukubwa"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Fanya shughuli zote ziweze kubadilishwa ukubwa kwenye madirisha mengi, bila kuzingatia thamani za faili ya maelezo."</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"Washa madirisha yenye muundo huru"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Ruhusu uwezo wa kutumia madirisha ya majaribio yenye muundo huru."</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"Washa madirisha yenye muundo huru (yaliyopitwa na wakati)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"Ruhusu matumizi ya madirisha ya majaribio yenye muundo huru yaliyopitwa na wakati."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Nenosiri la hifadhi rudufu ya eneo kazi"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Hifadhi rudufu kamili za eneo kazi hazijalindwa kwa sasa"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Gusa ili ubadilishe au uondoe nenosiri la hifadhi rudufu kamili za eneo kazi"</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 113a139176bb..47a65f6143b0 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"மேனிஃபெஸ்ட் மதிப்புகளைப் பொருட்படுத்தாமல், எல்லா ஆப்ஸையும் வெளிப்புறச் சேமிப்பிடத்தில் எழுத அனுமதிக்கும்"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"செயல்பாடுகளை அளவுமாறக்கூடியதாக அமை"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"மேனிஃபெஸ்ட் மதிப்புகளைப் பொருட்படுத்தாமல், பல சாளரத்திற்கு எல்லா செயல்பாடுகளையும் அளவுமாறக்கூடியதாக அமை."</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"குறிப்பிட்ட வடிவமில்லாத சாளரங்களை இயக்கு"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"சாளரங்களை அளவுமாற்ற மற்றும் எங்கும் நகர்த்த அனுமதிக்கும் பரிசோதனைக்குரிய அம்சத்திற்கான ஆதரவை இயக்கு."</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"குறிப்பிட்ட வடிவமில்லாத சாளரத்தை இயக்குதல் (லெகஸி)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"பரிசோதனைக்குரிய, குறிப்பிட்ட வடிவமில்லாத பழைய சாளரங்களுக்கான ஆதரவை இயக்குதல்."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"டெஸ்க்டாப் காப்புப்பிரதி கடவுச்சொல்"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"டெஸ்க்டாப்பின் முழு காப்புப்பிரதிகள் தற்போது பாதுகாக்கப்படவில்லை"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"டெஸ்க்டாப்பின் முழுக் காப்புப் பிரதிகளுக்கான கடவுச்சொல்லை மாற்ற அல்லது அகற்ற, தட்டவும்"</string>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index 83f2faaab9c8..11cbf2547241 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"ఏ యాప్‌ను అయినా మానిఫెస్ట్ విలువలతో సంబంధం లేకుండా బాహ్య స్టోరేజ్‌లో సేవ్ చేయడానికి అనుమతిస్తుంది"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"యాక్టివిటీ విండోల సైజ్‌ మార్చ‌గ‌లిగేలా నిర్బంధించు"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"మానిఫెస్ట్ విలువలతో సంబంధం లేకుండా అన్ని యాక్టివిటీస్‌ను పలు రకాల విండోల్లో సరిపోయేటట్లు సైజ్‌ మార్చగలిగేలా చేస్తుంది."</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"స్వతంత్ర రూప విండోలను ఎనేబుల్ చేయండి"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"ప్రయోగాత్మక స్వతంత్ర రూప విండోల కోసం సపోర్ట్‌ను ఎనేబుల్ చేస్తుంది."</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"ఫ్రీఫార్మ్ విండోలను ఎనేబుల్ చేయండి (లెగసీ)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"ప్రయోగాత్మక లెగసీ ఫ్రీఫార్మ్ విండోలకు సంబంధించిన సపోర్ట్‌ను ఎనేబుల్ చేయండి."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"డెస్క్‌టాప్ బ్యాకప్ పాస్‌వర్డ్"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"డెస్క్‌టాప్ పూర్తి బ్యాకప్‌లు ప్రస్తుతం రక్షించబడలేదు"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"డెస్క్‌టాప్ పూర్తి బ్యాకప్‌ల కోసం పాస్‌వర్డ్‌ను మార్చడానికి లేదా తీసివేయడానికి నొక్కండి"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index ef315924465d..40dbcad10a4a 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"ทำให้เขียนแอปในที่จัดเก็บข้อมูลภายนอกได้ โดยไม่คำนึงถึงค่าในไฟล์ Manifest"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"บังคับให้กิจกรรมปรับขนาดได้"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"ทำให้กิจกรรมทั้งหมดปรับขนาดได้สำหรับหน้าต่างหลายบาน โดยไม่คำนึงถึงค่าในไฟล์ Manifest"</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"เปิดใช้หน้าต่างรูปแบบอิสระ"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"เปิดการสนับสนุนหน้าต่างรูปแบบอิสระแบบทดลอง"</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"เปิดใช้หน้าต่างรูปแบบอิสระ (แบบเดิม)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"เปิดใช้การรองรับหน้าต่างรูปแบบอิสระแบบเดิมเวอร์ชันทดลอง"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"รหัสผ่านการสำรองข้อมูลในเดสก์ท็อป"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"การสำรองข้อมูลเต็มรูปแบบในเดสก์ท็อปไม่ได้รับการป้องกันในขณะนี้"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"แตะเพื่อเปลี่ยนแปลงหรือลบรหัสผ่านสำหรับการสำรองข้อมูลเต็มรูปแบบในเดสก์ท็อป"</string>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index 90acd6fa0647..221e634e037f 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Ginagawang kwalipikado ang anumang app na mailagay sa external na storage, anuman ang mga value ng manifest"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Sapilitang gawing resizable ang mga aktibidad"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Gawing nare-resize ang lahat ng aktibidad para sa multi-window, anuman ang mga value ng manifest."</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"I-enable ang mga freeform window"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"I-enable ang suporta para sa mga pang-eksperimentong freeform window."</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"I-enable ang mga freeform window (legacy)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"I-enable ang suporta para sa mga pang-eksperimentong legacy na freeform window."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Password ng pag-backup ng desktop"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Kasalukuyang hindi pinoprotektahan ang mga buong pag-backup ng desktop"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"I-tap upang baguhin o alisin ang password para sa mga kumpletong pag-back up sa desktop"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index a30c3ee5c24d..33c4b3a9c1d4 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Manifest değerlerinden bağımsız olarak uygulamaları harici depolamaya yazmak için uygun hale getirir"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Etkinlikleri yeniden boyutlandırılabilmeye zorla"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Manifest değerlerinden bağımsız olarak, tüm etkinlikleri birden fazla pencerede yeniden boyutlandırılabilir yap."</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"Serbest biçimli pencereleri etkinleştir"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Deneysel serbest biçimli pencere desteğini etkinleştir."</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"Serbest biçimli pencereleri (eski) etkinleştir"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"Deneysel eski serbest biçimli pencere desteğini etkinleştir."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Masaüstü yedekleme şifresi"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Masaüstü tam yedeklemeleri şu an korunmuyor"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Masaüstü tam yedeklemelerinin şifresini değiştirmek veya kaldırmak için dokunun"</string>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index c94e745bfcd4..ce4536f3630f 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Можна записувати додатки в зовнішню пам’ять, незалежно від значень у маніфесті"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Примусово масштабувати активність"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Масштабувати активність на кілька вікон, незалежно від значень у файлі маніфесту."</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"Увімкнути вікна довільного формату"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Увімкнути експериментальні вікна довільного формату."</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"Увімкнути старий формат вікон змінного розміру"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"Увімкнути підтримку експериментального старого формату вікон змінного розміру."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Пароль рез. копії на ПК"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Повні резервні копії на комп’ютері наразі не захищені"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Торкніться, щоб змінити або видалити пароль для повного резервного копіювання на комп’ютер"</string>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index 3d2c89c26fa3..d7f456198d7e 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"‏manifest اقدار سے قطع نظر، کسی بھی ایپ کو بیرونی اسٹوریج پر لکھے جانے کا اہل بناتا ہے"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"سرگرمیوں کو ری سائز ایبل بنائیں"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"مینی فیسٹ اقدار سے قطع نظر، ملٹی ونڈو کیلئے تمام سرگرمیوں کو ری سائز ایبل بنائیں۔"</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"‏freeform ونڈوز فعال کریں"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"تجرباتی فری فارم ونڈوز کیلئے سپورٹ فعال کریں۔"</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"‏فریفارم ونڈوز کو فعال کریں (legacy)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"‏تجرباتی legacy فری فارم ونڈوز کیلئے سپورٹ فعال کریں۔"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"ڈیسک ٹاپ کا بیک اپ پاس ورڈ"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"ڈیسک ٹاپ کے مکمل بیک اپس فی الحال محفوظ کیے ہوئے نہیں ہیں"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"ڈیسک ٹاپ کے مکمل بیک اپس کیلئے پاس ورڈ کو تبدیل کرنے یا ہٹانے کیلئے تھپتھپائیں"</string>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index 93ffac82a583..774dfc4f83ad 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Manifest qiymatidan qat’i nazar istalgan ilovani tashqi xotiraga saqlash imkonini beradi"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Harakatlarni moslashuvchan o‘lchamga keltirish"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Manifest qiymatidan qat’i nazar barcha harakatlarni ko‘p oynali rejimga moslashtirish."</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"Erkin shakldagi oynalarni yoqish"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Erkin shakldagi oynalar yaratish uchun mo‘ljallangan tajribaviy funksiyani yoqish."</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"Erkin shakldagi oynalarni (eskirgan) yoqish"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"Eskirgan erkin shakldagi oynalar yaratish uchun moʻljallangan tajribaviy funksiyani yoqish."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Zaxira nusxa uchun parol"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Kompyuterdagi zaxira nusxalar hozirgi vaqtda himoyalanmagan"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Ish stoli to‘liq zaxira nusxalari parolini o‘zgartirish yoki o‘chirish uchun bu yerni bosing"</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index 414ad37bf072..f66b13763225 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Cho phép ghi mọi ứng dụng đủ điều kiện vào bộ nhớ ngoài, bất kể giá trị tệp kê khai là gì"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Buộc các hoạt động có thể thay đổi kích thước"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Cho phép thay đổi kích thước của tất cả các hoạt động cho nhiều cửa sổ, bất kể giá trị tệp kê khai là gì."</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"Bật cửa sổ dạng tự do"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Bật tính năng hỗ trợ cửa sổ dạng tự do thử nghiệm."</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"Bật cửa sổ có thể đổi kích thước (cũ)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"Bật tính năng hỗ trợ cửa sổ có thể đổi kích thước thử nghiệm (cũ)."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Mật khẩu cho bản sao lưu qua máy tính"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Các bản sao lưu đầy đủ qua máy tính hiện không được bảo vệ"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Nhấn để thay đổi hoặc xóa mật khẩu dành cho các bản sao lưu đầy đủ vào máy tính"</string>
@@ -575,7 +575,7 @@
<string name="zen_mode_settings_summary_off" msgid="3832876036123504076">"Không bao giờ"</string>
<string name="zen_interruption_level_priority" msgid="5392140786447823299">"Chỉ cho các mục ưu tiên"</string>
<string name="zen_mode_and_condition" msgid="8877086090066332516">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
- <string name="zen_alarm_warning_indef" msgid="4146527909616457163">"Bạn sẽ không nghe thấy báo thức tiếp theo lúc <xliff:g id="WHEN">%1$s</xliff:g> của mình trừ khi bạn tắt chức năng này trước"</string>
+ <string name="zen_alarm_warning_indef" msgid="4146527909616457163">"Bạn sẽ không nghe thấy báo thức tiếp theo lúc <xliff:g id="WHEN">%1$s</xliff:g> của mình trừ phi bạn tắt chức năng này trước"</string>
<string name="zen_alarm_warning" msgid="245729928048586280">"Bạn sẽ không nghe thấy báo thức tiếp theo lúc <xliff:g id="WHEN">%1$s</xliff:g> của mình"</string>
<string name="alarm_template" msgid="3346777418136233330">"lúc <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="6382760514842998629">"vào <xliff:g id="WHEN">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index c0a8f2d51c31..2b6e8f841dd8 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"允许将任何应用写入外部存储设备(无论清单值是什么)"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"强制将 activity 设为可调整大小"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"将所有 activity 设为可配合多窗口环境调整大小(无论清单值是什么)。"</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"启用可自由调整的窗口"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"启用可自由调整的窗口这一实验性功能。"</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"启用可自由调整的窗口(旧版)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"实现对实验性旧版可自由调整的窗口的支持。"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"桌面备份密码"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"桌面完整备份当前未设置密码保护"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"点按即可更改或移除用于保护桌面完整备份的密码"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index 74f2678b1cce..97b6f666f4b2 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"在任何資訊清單值下,允許將所有符合資格的應用程式寫入到外部儲存完間"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"強制將活動設為可調整尺寸"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"在任何資訊清單值下,允許系統配合多重視窗環境調整所有活動的尺寸。"</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"啟用自由形態視窗"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"啟用實驗版自由形態視窗的支援功能。"</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"啟用自由形態視窗 (舊的)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"啟用舊的實驗版自由形態視窗的支援功能。"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"桌面電腦備份密碼"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"桌面電腦的完整備份目前未受保護"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"輕按即可變更或移除桌面電腦完整備份的密碼"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index 5b068e35daa1..348b1f63d757 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"允許將任何應用程式寫入外部儲存空間 (無論資訊清單值為何)"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"將活動強制設為可調整大小"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"將所有活動設為可配合多重視窗環境調整大小 (無論資訊清單值為何)。"</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"啟用自由形式視窗"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"啟用實驗版自由形式視窗的支援功能。"</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"啟用自由形式視窗 (舊版)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"啟用實驗性舊版自由形式視窗支援功能。"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"電腦備份密碼"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"尚未設定密碼保護電腦的完整備份"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"輕觸即可變更或移除電腦完整備份的密碼"</string>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index da152cefaf49..9cc474c945db 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -436,8 +436,8 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Yenza noma uluphi uhlelo lokusebenza lifaneleke ukuthi libhalwe kusitoreji sangaphandle, ngaphandle kwamavelu we-manifest"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Imisebenzi yamandla izonikezwa usayizi omusha"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Yenza yonke imisebenzi ibe nosayizi abasha kumawindi amaningi, ngokunganaki amavelu e-manifest."</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"Nika amandla amawindi e-freeform"</string>
- <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Nika amandla usekelo lwe-windows yokuhlola kwe-freeform."</string>
+ <string name="enable_freeform_support" msgid="8409932201445109106">"Vumela amawindi efreeform (ifa)"</string>
+ <string name="enable_freeform_support_summary" msgid="2242481082356957934">"Nika amandla amawindi efreeform efa elisahlolwa."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Iphasiwedi yokusekela ngokulondoloza ye-Desktop"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Ukusekela ngokulondoloza okugcwele kwe-Desktop akuvikelekile okwamanje."</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Thepha ukushintsha noma ukususa iphasiwedi yokwenziwa kwezipele ngokugcwele kwideskithophu"</string>
diff --git a/packages/SettingsLib/res/values/colors.xml b/packages/SettingsLib/res/values/colors.xml
index f89fe935df38..67139b510d85 100644
--- a/packages/SettingsLib/res/values/colors.xml
+++ b/packages/SettingsLib/res/values/colors.xml
@@ -14,8 +14,7 @@
limitations under the License.
-->
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
+<resources>
<color name="disabled_text_color">#66000000</color> <!-- 38% black -->
<color name="bt_color_icon_1">#b4a50e0e</color> <!-- 72% Material Red 900 -->
@@ -34,8 +33,8 @@
<color name="bt_color_bg_6">#e9d2fd</color> <!-- Material Purple 100 -->
<color name="bt_color_bg_7">#cbf0f8</color> <!-- Material Cyan 100 -->
- <color name="black">@*android:color/black</color>
- <color name="white">@*android:color/white</color>
+ <color name="dark_mode_icon_color_single_tone">#99000000</color>
+ <color name="light_mode_icon_color_single_tone">#ffffff</color>
<color name="user_avatar_color_bg">?android:attr/colorBackgroundFloating</color>
diff --git a/packages/SettingsLib/src/com/android/settingslib/graph/SignalDrawable.java b/packages/SettingsLib/src/com/android/settingslib/graph/SignalDrawable.java
index 6c2bd412cfbd..ef0f6cbc6ed9 100644
--- a/packages/SettingsLib/src/com/android/settingslib/graph/SignalDrawable.java
+++ b/packages/SettingsLib/src/com/android/settingslib/graph/SignalDrawable.java
@@ -100,9 +100,9 @@ public class SignalDrawable extends DrawableWrapper {
mCutoutHeightFraction = context.getResources().getFloat(
com.android.internal.R.dimen.config_signalCutoutHeightFraction);
mDarkModeFillColor = Utils.getColorStateListDefaultColor(context,
- R.color.black);
+ R.color.dark_mode_icon_color_single_tone);
mLightModeFillColor = Utils.getColorStateListDefaultColor(context,
- R.color.white);
+ R.color.light_mode_icon_color_single_tone);
mIntrinsicSize = context.getResources().getDimensionPixelSize(R.dimen.signal_icon_size);
mTransparentPaint.setColor(context.getColor(android.R.color.transparent));
mTransparentPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/RouterInfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/RouterInfoMediaManager.java
index 6571dd7ba398..eced7b3a116b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/RouterInfoMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/RouterInfoMediaManager.java
@@ -29,6 +29,7 @@ import android.media.session.MediaController;
import android.os.UserHandle;
import android.text.TextUtils;
+import androidx.annotation.GuardedBy;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -41,7 +42,6 @@ import java.util.HashMap;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
-import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import java.util.stream.Collectors;
@@ -65,7 +65,9 @@ public final class RouterInfoMediaManager extends InfoMediaManager {
refreshDevices();
};
- private final AtomicReference<MediaRouter2.ScanToken> mScanToken = new AtomicReference<>();
+ @GuardedBy("this")
+ @Nullable
+ private MediaRouter2.ScanToken mScanToken;
// TODO (b/321969740): Plumb target UserHandle between UMO and RouterInfoMediaManager.
/* package */ RouterInfoMediaManager(
@@ -101,8 +103,13 @@ public final class RouterInfoMediaManager extends InfoMediaManager {
@Override
protected void startScanOnRouter() {
if (Flags.enableScreenOffScanning()) {
- MediaRouter2.ScanRequest request = new MediaRouter2.ScanRequest.Builder().build();
- mScanToken.compareAndSet(null, mRouter.requestScan(request));
+ synchronized (this) {
+ if (mScanToken == null) {
+ MediaRouter2.ScanRequest request =
+ new MediaRouter2.ScanRequest.Builder().build();
+ mScanToken = mRouter.requestScan(request);
+ }
+ }
} else {
mRouter.startScan();
}
@@ -120,9 +127,11 @@ public final class RouterInfoMediaManager extends InfoMediaManager {
@Override
protected void stopScanOnRouter() {
if (Flags.enableScreenOffScanning()) {
- MediaRouter2.ScanToken token = mScanToken.getAndSet(null);
- if (token != null) {
- mRouter.cancelScanRequest(token);
+ synchronized (this) {
+ if (mScanToken != null) {
+ mRouter.cancelScanRequest(mScanToken);
+ mScanToken = null;
+ }
}
} else {
mRouter.stopScan();
diff --git a/packages/SettingsLib/src/com/android/settingslib/mobile/dataservice/DataServiceUtils.java b/packages/SettingsLib/src/com/android/settingslib/mobile/dataservice/DataServiceUtils.java
index 8868837e4cff..4028b73a2c71 100644
--- a/packages/SettingsLib/src/com/android/settingslib/mobile/dataservice/DataServiceUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/mobile/dataservice/DataServiceUtils.java
@@ -105,12 +105,6 @@ public class DataServiceUtils {
public static final String COLUMN_CARD_STATE = "cardState";
/**
- * The name of the extended APDU supported state column, see
- * {@link UiccSlotInfo#getIsExtendedApduSupported()}.
- */
- public static final String COLUMN_IS_EXTENDED_APDU_SUPPORTED = "isExtendedApduSupported";
-
- /**
* The name of the removable state column, see {@link UiccSlotInfo#isRemovable()}.
*/
public static final String COLUMN_IS_REMOVABLE = "isRemovable";
@@ -150,74 +144,17 @@ public class DataServiceUtils {
public static final String COLUMN_SIM_SLOT_INDEX = "simSlotIndex";
/**
- * The name of the carrier ID column, see {@link SubscriptionInfo#getCarrierId()}.
- */
- public static final String COLUMN_CARRIER_ID = "carrierId";
-
- /**
- * The name of the display name column, see {@link SubscriptionInfo#getDisplayName()}.
- */
- public static final String COLUMN_DISPLAY_NAME = "displayName";
-
- /**
- * The name of the carrier name column, see {@link SubscriptionInfo#getCarrierName()}.
- */
- public static final String COLUMN_CARRIER_NAME = "carrierName";
-
- /**
- * The name of the data roaming state column, see
- * {@link SubscriptionInfo#getDataRoaming()}.
- */
- public static final String COLUMN_DATA_ROAMING = "dataRoaming";
-
- /**
- * The name of the mcc column, see {@link SubscriptionInfo#getMccString()}.
- */
- public static final String COLUMN_MCC = "mcc";
-
- /**
- * The name of the mnc column, see {@link SubscriptionInfo#getMncString()}.
- */
- public static final String COLUMN_MNC = "mnc";
-
- /**
- * The name of the country ISO column, see {@link SubscriptionInfo#getCountryIso()}.
- */
- public static final String COLUMN_COUNTRY_ISO = "countryIso";
-
- /**
* The name of the embedded state column, see {@link SubscriptionInfo#isEmbedded()}.
*/
public static final String COLUMN_IS_EMBEDDED = "isEmbedded";
/**
- * The name of the card ID column, see {@link SubscriptionInfo#getCardId()}.
- */
- public static final String COLUMN_CARD_ID = "cardId";
-
- /**
- * The name of the port index column, see {@link SubscriptionInfo#getPortIndex()}.
- */
- public static final String COLUMN_PORT_INDEX = "portIndex";
-
- /**
* The name of the opportunistic state column, see
* {@link SubscriptionInfo#isOpportunistic()}.
*/
public static final String COLUMN_IS_OPPORTUNISTIC = "isOpportunistic";
/**
- * The name of the groupUUID column, see {@link SubscriptionInfo#getGroupUuid()}.
- */
- public static final String COLUMN_GROUP_UUID = "groupUUID";
-
- /**
- * The name of the subscription type column, see
- * {@link SubscriptionInfo#getSubscriptionType()}}.
- */
- public static final String COLUMN_SUBSCRIPTION_TYPE = "subscriptionType";
-
- /**
* The name of the uniqueName column,
* {@see SubscriptionUtil#getUniqueSubscriptionDisplayName(SubscriptionInfo, Context)}.
*/
@@ -231,19 +168,6 @@ public class DataServiceUtils {
public static final String COLUMN_IS_SUBSCRIPTION_VISIBLE = "isSubscriptionVisible";
/**
- * The name of the formatted phone number column,
- * {@see SubscriptionUtil#getFormattedPhoneNumber(Context, SubscriptionInfo)}.
- */
- public static final String COLUMN_FORMATTED_PHONE_NUMBER = "getFormattedPhoneNumber";
-
- /**
- * The name of the first removable subscription state column,
- * {@see SubscriptionUtil#getFirstRemovableSubscription(Context)}.
- */
- public static final String COLUMN_IS_FIRST_REMOVABLE_SUBSCRIPTION =
- "isFirstRemovableSubscription";
-
- /**
* The name of the default subscription selection column,
* {@see SubscriptionUtil#getSubscriptionOrDefault(Context, int)}.
*/
@@ -257,24 +181,12 @@ public class DataServiceUtils {
public static final String COLUMN_IS_VALID_SUBSCRIPTION = "isValidSubscription";
/**
- * The name of the usable subscription column,
- * {@link SubscriptionManager#isUsableSubscriptionId(int)}.
- */
- public static final String COLUMN_IS_USABLE_SUBSCRIPTION = "isUsableSubscription";
-
- /**
* The name of the active subscription column,
* {@link SubscriptionManager#isActiveSubscriptionId(int)}.
*/
public static final String COLUMN_IS_ACTIVE_SUBSCRIPTION_ID = "isActiveSubscription";
/**
- * The name of the available subscription column,
- * {@see SubscriptionUtil#getAvailableSubscription(Context, ProxySubscriptionManager, int)}.
- */
- public static final String COLUMN_IS_AVAILABLE_SUBSCRIPTION = "isAvailableSubscription";
-
- /**
* The name of the active data subscription state column, see
* {@link SubscriptionManager#getActiveDataSubscriptionId()}.
*/
diff --git a/packages/SettingsLib/src/com/android/settingslib/mobile/dataservice/SubscriptionInfoDao.java b/packages/SettingsLib/src/com/android/settingslib/mobile/dataservice/SubscriptionInfoDao.java
index e6b1cfb440fa..060eab6681c6 100644
--- a/packages/SettingsLib/src/com/android/settingslib/mobile/dataservice/SubscriptionInfoDao.java
+++ b/packages/SettingsLib/src/com/android/settingslib/mobile/dataservice/SubscriptionInfoDao.java
@@ -40,15 +40,6 @@ public interface SubscriptionInfoDao {
+ DataServiceUtils.SubscriptionInfoData.COLUMN_ID + " = :subId")
SubscriptionInfoEntity querySubInfoById(String subId);
- @Query("SELECT * FROM " + DataServiceUtils.SubscriptionInfoData.TABLE_NAME + " WHERE "
- + DataServiceUtils.SubscriptionInfoData.COLUMN_IS_ACTIVE_SUBSCRIPTION_ID
- + " = :isActiveSubscription" + " AND "
- + DataServiceUtils.SubscriptionInfoData.COLUMN_IS_SUBSCRIPTION_VISIBLE
- + " = :isSubscriptionVisible" + " ORDER BY "
- + DataServiceUtils.SubscriptionInfoData.COLUMN_SIM_SLOT_INDEX)
- LiveData<List<SubscriptionInfoEntity>> queryActiveSubInfos(
- boolean isActiveSubscription, boolean isSubscriptionVisible);
-
@Query("SELECT COUNT(*) FROM " + DataServiceUtils.SubscriptionInfoData.TABLE_NAME)
int count();
diff --git a/packages/SettingsLib/src/com/android/settingslib/mobile/dataservice/SubscriptionInfoEntity.java b/packages/SettingsLib/src/com/android/settingslib/mobile/dataservice/SubscriptionInfoEntity.java
index 361a24612b3a..88e6a57bf45b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/mobile/dataservice/SubscriptionInfoEntity.java
+++ b/packages/SettingsLib/src/com/android/settingslib/mobile/dataservice/SubscriptionInfoEntity.java
@@ -19,7 +19,6 @@ package com.android.settingslib.mobile.dataservice;
import android.text.TextUtils;
import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
import androidx.room.ColumnInfo;
import androidx.room.Entity;
import androidx.room.PrimaryKey;
@@ -28,39 +27,19 @@ import java.util.Objects;
@Entity(tableName = DataServiceUtils.SubscriptionInfoData.TABLE_NAME)
public class SubscriptionInfoEntity {
- public SubscriptionInfoEntity(@NonNull String subId, int simSlotIndex, int carrierId,
- String displayName, String carrierName, int dataRoaming, String mcc, String mnc,
- String countryIso, boolean isEmbedded, int cardId, int portIndex,
- boolean isOpportunistic, @Nullable String groupUUID, int subscriptionType,
- String uniqueName, boolean isSubscriptionVisible, @Nullable String formattedPhoneNumber,
- boolean isFirstRemovableSubscription, boolean isDefaultSubscriptionSelection,
- boolean isValidSubscription, boolean isUsableSubscription,
- boolean isActiveSubscriptionId, boolean isAvailableSubscription,
- boolean isActiveDataSubscriptionId) {
+ public SubscriptionInfoEntity(@NonNull String subId, int simSlotIndex, boolean isEmbedded,
+ boolean isOpportunistic, String uniqueName, boolean isSubscriptionVisible,
+ boolean isDefaultSubscriptionSelection, boolean isValidSubscription,
+ boolean isActiveSubscriptionId, boolean isActiveDataSubscriptionId) {
this.subId = subId;
this.simSlotIndex = simSlotIndex;
- this.carrierId = carrierId;
- this.displayName = displayName;
- this.carrierName = carrierName;
- this.dataRoaming = dataRoaming;
- this.mcc = mcc;
- this.mnc = mnc;
- this.countryIso = countryIso;
this.isEmbedded = isEmbedded;
- this.cardId = cardId;
- this.portIndex = portIndex;
this.isOpportunistic = isOpportunistic;
- this.groupUUID = groupUUID;
- this.subscriptionType = subscriptionType;
this.uniqueName = uniqueName;
this.isSubscriptionVisible = isSubscriptionVisible;
- this.formattedPhoneNumber = formattedPhoneNumber;
- this.isFirstRemovableSubscription = isFirstRemovableSubscription;
this.isDefaultSubscriptionSelection = isDefaultSubscriptionSelection;
this.isValidSubscription = isValidSubscription;
- this.isUsableSubscription = isUsableSubscription;
this.isActiveSubscriptionId = isActiveSubscriptionId;
- this.isAvailableSubscription = isAvailableSubscription;
this.isActiveDataSubscriptionId = isActiveDataSubscriptionId;
}
@@ -72,59 +51,18 @@ public class SubscriptionInfoEntity {
@ColumnInfo(name = DataServiceUtils.SubscriptionInfoData.COLUMN_SIM_SLOT_INDEX)
public int simSlotIndex;
- @ColumnInfo(name = DataServiceUtils.SubscriptionInfoData.COLUMN_CARRIER_ID)
- public int carrierId;
-
- @ColumnInfo(name = DataServiceUtils.SubscriptionInfoData.COLUMN_DISPLAY_NAME)
- public String displayName;
-
- @ColumnInfo(name = DataServiceUtils.SubscriptionInfoData.COLUMN_CARRIER_NAME)
- public String carrierName;
-
- @ColumnInfo(name = DataServiceUtils.SubscriptionInfoData.COLUMN_DATA_ROAMING)
- public int dataRoaming;
-
- @ColumnInfo(name = DataServiceUtils.SubscriptionInfoData.COLUMN_MCC)
- public String mcc;
-
- @ColumnInfo(name = DataServiceUtils.SubscriptionInfoData.COLUMN_MNC)
- public String mnc;
-
- @ColumnInfo(name = DataServiceUtils.SubscriptionInfoData.COLUMN_COUNTRY_ISO)
- public String countryIso;
-
@ColumnInfo(name = DataServiceUtils.SubscriptionInfoData.COLUMN_IS_EMBEDDED)
public boolean isEmbedded;
- @ColumnInfo(name = DataServiceUtils.SubscriptionInfoData.COLUMN_CARD_ID)
- public int cardId;
-
- @ColumnInfo(name = DataServiceUtils.SubscriptionInfoData.COLUMN_PORT_INDEX)
- public int portIndex;
-
@ColumnInfo(name = DataServiceUtils.SubscriptionInfoData.COLUMN_IS_OPPORTUNISTIC)
public boolean isOpportunistic;
- @ColumnInfo(name = DataServiceUtils.SubscriptionInfoData.COLUMN_GROUP_UUID)
- @Nullable
- public String groupUUID;
-
- @ColumnInfo(name = DataServiceUtils.SubscriptionInfoData.COLUMN_SUBSCRIPTION_TYPE)
- public int subscriptionType;
-
@ColumnInfo(name = DataServiceUtils.SubscriptionInfoData.COLUMN_UNIQUE_NAME)
public String uniqueName;
@ColumnInfo(name = DataServiceUtils.SubscriptionInfoData.COLUMN_IS_SUBSCRIPTION_VISIBLE)
public boolean isSubscriptionVisible;
- @ColumnInfo(name = DataServiceUtils.SubscriptionInfoData.COLUMN_FORMATTED_PHONE_NUMBER)
- @Nullable
- public String formattedPhoneNumber;
-
- @ColumnInfo(name = DataServiceUtils.SubscriptionInfoData.COLUMN_IS_FIRST_REMOVABLE_SUBSCRIPTION)
- public boolean isFirstRemovableSubscription;
-
@ColumnInfo(name =
DataServiceUtils.SubscriptionInfoData.COLUMN_IS_DEFAULT_SUBSCRIPTION_SELECTION)
public boolean isDefaultSubscriptionSelection;
@@ -132,15 +70,9 @@ public class SubscriptionInfoEntity {
@ColumnInfo(name = DataServiceUtils.SubscriptionInfoData.COLUMN_IS_VALID_SUBSCRIPTION)
public boolean isValidSubscription;
- @ColumnInfo(name = DataServiceUtils.SubscriptionInfoData.COLUMN_IS_USABLE_SUBSCRIPTION)
- public boolean isUsableSubscription;
-
@ColumnInfo(name = DataServiceUtils.SubscriptionInfoData.COLUMN_IS_ACTIVE_SUBSCRIPTION_ID)
public boolean isActiveSubscriptionId;
- @ColumnInfo(name = DataServiceUtils.SubscriptionInfoData.COLUMN_IS_AVAILABLE_SUBSCRIPTION)
- public boolean isAvailableSubscription;
-
@ColumnInfo(name = DataServiceUtils.SubscriptionInfoData.COLUMN_IS_ACTIVE_DATA_SUBSCRIPTION)
public boolean isActiveDataSubscriptionId;
@@ -165,28 +97,13 @@ public class SubscriptionInfoEntity {
return Objects.hash(
subId,
simSlotIndex,
- carrierId,
- displayName,
- carrierName,
- dataRoaming,
- mcc,
- mnc,
- countryIso,
isEmbedded,
- cardId,
- portIndex,
isOpportunistic,
- groupUUID,
- subscriptionType,
uniqueName,
isSubscriptionVisible,
- formattedPhoneNumber,
- isFirstRemovableSubscription,
isDefaultSubscriptionSelection,
isValidSubscription,
- isUsableSubscription,
isActiveSubscriptionId,
- isAvailableSubscription,
isActiveDataSubscriptionId);
}
@@ -202,28 +119,13 @@ public class SubscriptionInfoEntity {
SubscriptionInfoEntity info = (SubscriptionInfoEntity) obj;
return TextUtils.equals(subId, info.subId)
&& simSlotIndex == info.simSlotIndex
- && carrierId == info.carrierId
- && TextUtils.equals(displayName, info.displayName)
- && TextUtils.equals(carrierName, info.carrierName)
- && dataRoaming == info.dataRoaming
- && TextUtils.equals(mcc, info.mcc)
- && TextUtils.equals(mnc, info.mnc)
- && TextUtils.equals(countryIso, info.countryIso)
&& isEmbedded == info.isEmbedded
- && cardId == info.cardId
- && portIndex == info.portIndex
&& isOpportunistic == info.isOpportunistic
- && TextUtils.equals(groupUUID, info.groupUUID)
- && subscriptionType == info.subscriptionType
&& TextUtils.equals(uniqueName, info.uniqueName)
&& isSubscriptionVisible == info.isSubscriptionVisible
- && TextUtils.equals(formattedPhoneNumber, info.formattedPhoneNumber)
- && isFirstRemovableSubscription == info.isFirstRemovableSubscription
&& isDefaultSubscriptionSelection == info.isDefaultSubscriptionSelection
&& isValidSubscription == info.isValidSubscription
- && isUsableSubscription == info.isUsableSubscription
&& isActiveSubscriptionId == info.isActiveSubscriptionId
- && isAvailableSubscription == info.isAvailableSubscription
&& isActiveDataSubscriptionId == info.isActiveDataSubscriptionId;
}
@@ -233,50 +135,20 @@ public class SubscriptionInfoEntity {
.append(subId)
.append(", simSlotIndex = ")
.append(simSlotIndex)
- .append(", carrierId = ")
- .append(carrierId)
- .append(", displayName = ")
- .append(displayName)
- .append(", carrierName = ")
- .append(carrierName)
- .append(", dataRoaming = ")
- .append(dataRoaming)
- .append(", mcc = ")
- .append(mcc)
- .append(", mnc = ")
- .append(mnc)
- .append(", countryIso = ")
- .append(countryIso)
.append(", isEmbedded = ")
.append(isEmbedded)
- .append(", cardId = ")
- .append(cardId)
- .append(", portIndex = ")
- .append(portIndex)
.append(", isOpportunistic = ")
.append(isOpportunistic)
- .append(", groupUUID = ")
- .append(groupUUID)
- .append(", subscriptionType = ")
- .append(subscriptionType)
.append(", uniqueName = ")
.append(uniqueName)
.append(", isSubscriptionVisible = ")
.append(isSubscriptionVisible)
- .append(", formattedPhoneNumber = ")
- .append(formattedPhoneNumber)
- .append(", isFirstRemovableSubscription = ")
- .append(isFirstRemovableSubscription)
.append(", isDefaultSubscriptionSelection = ")
.append(isDefaultSubscriptionSelection)
.append(", isValidSubscription = ")
.append(isValidSubscription)
- .append(", isUsableSubscription = ")
- .append(isUsableSubscription)
.append(", isActiveSubscriptionId = ")
.append(isActiveSubscriptionId)
- .append(", isAvailableSubscription = ")
- .append(isAvailableSubscription)
.append(", isActiveDataSubscriptionId = ")
.append(isActiveDataSubscriptionId)
.append(")}");
diff --git a/packages/SettingsLib/src/com/android/settingslib/notification/data/repository/ZenModeRepository.kt b/packages/SettingsLib/src/com/android/settingslib/notification/data/repository/ZenModeRepository.kt
index 273a63db801c..72c3c1719f70 100644
--- a/packages/SettingsLib/src/com/android/settingslib/notification/data/repository/ZenModeRepository.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/notification/data/repository/ZenModeRepository.kt
@@ -56,7 +56,7 @@ class ZenModeRepositoryImpl(
val backgroundHandler: Handler?,
) : ZenModeRepository {
- private val notificationBroadcasts =
+ private val notificationBroadcasts by lazy {
callbackFlow {
val receiver =
object : BroadcastReceiver() {
@@ -95,8 +95,9 @@ class ZenModeRepositoryImpl(
)
}
}
+ }
- override val consolidatedNotificationPolicy: StateFlow<NotificationManager.Policy?> =
+ override val consolidatedNotificationPolicy: StateFlow<NotificationManager.Policy?> by lazy {
if (Flags.volumePanelBroadcastFix() && android.app.Flags.modesApi())
flowFromBroadcast(NotificationManager.ACTION_CONSOLIDATED_NOTIFICATION_POLICY_CHANGED) {
notificationManager.consolidatedNotificationPolicy
@@ -105,11 +106,13 @@ class ZenModeRepositoryImpl(
flowFromBroadcast(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED) {
notificationManager.consolidatedNotificationPolicy
}
+ }
- override val globalZenMode: StateFlow<Int?> =
+ override val globalZenMode: StateFlow<Int?> by lazy {
flowFromBroadcast(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED) {
notificationManager.zenMode
}
+ }
private fun <T> flowFromBroadcast(intentAction: String, mapper: () -> T) =
notificationBroadcasts
diff --git a/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenMode.java b/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenMode.java
index 2cc911234404..03a2b7526f62 100644
--- a/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenMode.java
+++ b/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenMode.java
@@ -286,11 +286,7 @@ public class ZenMode implements Parcelable {
mRule, oldCondition, conditionId));
}
- public boolean canEditName() {
- return !isManualDnd();
- }
-
- public boolean canEditIcon() {
+ public boolean canEditNameAndIcon() {
return !isManualDnd();
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/data/repository/ZenModeRepositoryTest.kt b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/data/repository/ZenModeRepositoryTest.kt
index 096c25db8629..06333b61eeb1 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/data/repository/ZenModeRepositoryTest.kt
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/data/repository/ZenModeRepositoryTest.kt
@@ -48,7 +48,6 @@ import org.robolectric.RobolectricTestRunner
@RunWith(RobolectricTestRunner::class)
@SmallTest
class ZenModeRepositoryTest {
-
@Mock private lateinit var context: Context
@Mock private lateinit var notificationManager: NotificationManager
@@ -73,7 +72,7 @@ class ZenModeRepositoryTest {
)
}
- @DisableFlags(android.app.Flags.FLAG_MODES_API, Flags.FLAG_VOLUME_PANEL_BROADCAST_FIX)
+ @DisableFlags(Flags.FLAG_VOLUME_PANEL_BROADCAST_FIX)
@Test
fun consolidatedPolicyChanges_repositoryEmits_flagsOff() {
testScope.runTest {
@@ -88,9 +87,7 @@ class ZenModeRepositoryTest {
triggerIntent(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED)
runCurrent()
- assertThat(values)
- .containsExactlyElementsIn(listOf(null, testPolicy1, testPolicy2))
- .inOrder()
+ assertThat(values).containsExactly(null, testPolicy1, testPolicy2).inOrder()
}
}
@@ -109,9 +106,7 @@ class ZenModeRepositoryTest {
triggerIntent(NotificationManager.ACTION_CONSOLIDATED_NOTIFICATION_POLICY_CHANGED)
runCurrent()
- assertThat(values)
- .containsExactlyElementsIn(listOf(null, testPolicy1, testPolicy2))
- .inOrder()
+ assertThat(values).containsExactly(null, testPolicy1, testPolicy2).inOrder()
}
}
@@ -128,14 +123,13 @@ class ZenModeRepositoryTest {
runCurrent()
assertThat(values)
- .containsExactlyElementsIn(
- listOf(null, Global.ZEN_MODE_OFF, Global.ZEN_MODE_ALARMS))
+ .containsExactly(null, Global.ZEN_MODE_OFF, Global.ZEN_MODE_ALARMS)
.inOrder()
}
}
private fun triggerIntent(action: String) {
- verify(context).registerReceiver(receiverCaptor.capture(), any())
+ verify(context).registerReceiver(receiverCaptor.capture(), any(), any(), any())
receiverCaptor.value.onReceive(context, Intent(action))
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/modes/ZenModeTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/modes/ZenModeTest.java
index 9e543122e707..e705f97202a3 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/modes/ZenModeTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/modes/ZenModeTest.java
@@ -56,12 +56,14 @@ public class ZenModeTest {
assertThat(zenMode.getId()).isEqualTo("id");
assertThat(zenMode.getRule()).isEqualTo(ZEN_RULE);
assertThat(zenMode.isManualDnd()).isFalse();
+ assertThat(zenMode.canEditNameAndIcon()).isTrue();
assertThat(zenMode.canBeDeleted()).isTrue();
assertThat(zenMode.isActive()).isTrue();
ZenMode manualMode = ZenMode.manualDndMode(ZEN_RULE, false);
assertThat(manualMode.getId()).isEqualTo(ZenMode.MANUAL_DND_MODE_ID);
assertThat(manualMode.isManualDnd()).isTrue();
+ assertThat(manualMode.canEditNameAndIcon()).isFalse();
assertThat(manualMode.canBeDeleted()).isFalse();
assertThat(manualMode.isActive()).isFalse();
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java b/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
index e77cf2fa6543..8b0772bb644d 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
@@ -42,6 +42,7 @@ import android.provider.Settings.Config.SyncDisabledMode;
import android.provider.UpdatableDeviceConfigServiceReadiness;
import android.util.Slog;
+import com.android.internal.pm.pkg.component.AconfigFlags;
import com.android.internal.util.FastPrintWriter;
import java.io.File;
@@ -189,22 +190,13 @@ public final class DeviceConfigService extends Binder {
public static HashMap<String, String> getAllFlags(IContentProvider provider) {
HashMap<String, String> allFlags = new HashMap<String, String>();
- try {
- Bundle args = new Bundle();
- args.putInt(Settings.CALL_METHOD_USER_KEY,
- ActivityManager.getService().getCurrentUser().id);
- Bundle b = provider.call(new AttributionSource(Process.myUid(),
- resolveCallingPackage(), null), Settings.AUTHORITY,
- Settings.CALL_METHOD_LIST_CONFIG, null, args);
- if (b != null) {
- Map<String, String> flagsToValues =
- (HashMap) b.getSerializable(Settings.NameValueTable.VALUE);
- allFlags.putAll(flagsToValues);
+ for (DeviceConfig.Properties properties : DeviceConfig.getAllProperties()) {
+ List<String> keys = new ArrayList<>(properties.getKeyset());
+ for (String flagName : properties.getKeyset()) {
+ String fullName = properties.getNamespace() + "/" + flagName;
+ allFlags.put(fullName, properties.getString(flagName, null));
}
- } catch (RemoteException e) {
- throw new RuntimeException("Failed in IPC", e);
}
-
return allFlags;
}
@@ -425,7 +417,13 @@ public final class DeviceConfigService extends Binder {
DeviceConfig.setProperty(namespace, key, value, makeDefault);
break;
case OVERRIDE:
- DeviceConfig.setLocalOverride(namespace, key, value);
+ AconfigFlags.Permission permission =
+ (new AconfigFlags()).getFlagPermission(key);
+ if (permission == AconfigFlags.Permission.READ_ONLY) {
+ pout.println("cannot override read-only flag " + key);
+ } else {
+ DeviceConfig.setLocalOverride(namespace, key, value);
+ }
break;
case CLEAR_OVERRIDE:
DeviceConfig.clearLocalOverride(namespace, key);
diff --git a/packages/Shell/res/values-fr-rCA/strings.xml b/packages/Shell/res/values-fr-rCA/strings.xml
index 54ae9542c032..760905049c88 100644
--- a/packages/Shell/res/values-fr-rCA/strings.xml
+++ b/packages/Shell/res/values-fr-rCA/strings.xml
@@ -28,7 +28,7 @@
<string name="bugreport_finished_pending_screenshot_text" product="tv" msgid="2343263822812016950">"Sélectionnez pour partager le rapport de bogue sans saisie d\'écran ou attendez que la saisie soit prête"</string>
<string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Touchez pour partager le rapport de bogue sans saisie d\'écran ou attendez que la saisie soit prête"</string>
<string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Touchez pour partager le rapport de bogue sans saisie d\'écran ou attendez que la saisie soit prête"</string>
- <string name="bugreport_confirm" msgid="5917407234515812495">"Les rapports de bogue contiennent des données des fichiers journaux du système, y compris des données que vous considérez comme sensibles (comme des renseignements sur l\'utilisation des applications et des données de localisation). Ne partagez les rapports de bogue qu\'avec les applications et les personnes en qui vous avez confiance."</string>
+ <string name="bugreport_confirm" msgid="5917407234515812495">"Les rapports de bogue contiennent des données des fichiers journaux du système, y compris des données que vous considérez comme sensibles (comme des renseignements sur l\'utilisation des applis et des données de localisation). Ne partagez les rapports de bogue qu\'avec les applis et les personnes en qui vous avez confiance."</string>
<string name="bugreport_confirm_dont_repeat" msgid="6179945398364357318">"Ne plus afficher"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Rapports de bogues"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Impossible de lire le fichier du rapport de bogue"</string>
diff --git a/packages/Shell/res/values-nb/strings.xml b/packages/Shell/res/values-nb/strings.xml
index 876bd9d7548f..db83f295ed87 100644
--- a/packages/Shell/res/values-nb/strings.xml
+++ b/packages/Shell/res/values-nb/strings.xml
@@ -35,7 +35,7 @@
<string name="bugreport_add_details_to_zip_failed" msgid="1302931926486712371">"Kunne ikke legge til informasjon fra feilrapporten i ZIP-filen"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"uten navn"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Detaljer"</string>
- <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Skjermdump"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Skjermbilde"</string>
<string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Skjermdumpen er tatt."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Skjermdumpen kunne ikke tas."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detaljer om feilrapport <xliff:g id="ID">#%d</xliff:g>"</string>
diff --git a/packages/SimAppDialog/res/values-fr-rCA/strings.xml b/packages/SimAppDialog/res/values-fr-rCA/strings.xml
index b6075855a3bb..0ce7a2a5db1c 100644
--- a/packages/SimAppDialog/res/values-fr-rCA/strings.xml
+++ b/packages/SimAppDialog/res/values-fr-rCA/strings.xml
@@ -17,10 +17,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="8898068901680117589">"Boîte de dialogue de l\'application SIM"</string>
+ <string name="app_name" msgid="8898068901680117589">"Boîte de dialogue de l\'appli SIM"</string>
<string name="install_carrier_app_title" msgid="334729104862562585">"Activer le service cellulaire"</string>
- <string name="install_carrier_app_description" msgid="4014303558674923797">"Pour que le nouveau module SIM fonctionne correctement, vous devez installer l\'application <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="install_carrier_app_description" msgid="4014303558674923797">"Pour que le nouveau module SIM fonctionne correctement, vous devez installer l\'appli <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="install_carrier_app_description_default" msgid="7356830245205847840">"Pour que le nouveau module SIM fonctionne, vous devez installer l\'appli du fournisseur de services"</string>
<string name="install_carrier_app_defer_action" msgid="2558576736886876209">"Pas maintenant"</string>
- <string name="install_carrier_app_download_action" msgid="7859229305958538064">"Télécharger l\'application"</string>
+ <string name="install_carrier_app_download_action" msgid="7859229305958538064">"Télécharger l\'appli"</string>
</resources>
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 9cbb1bd9c71c..187187326ad5 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -581,7 +581,6 @@ android_library {
"androidx.activity_activity-compose",
"androidx.compose.animation_animation-graphics",
"androidx.lifecycle_lifecycle-viewmodel-compose",
- "device_policy_aconfig_flags_lib",
],
libs: [
"keepanno-annotations",
@@ -669,6 +668,7 @@ android_library {
],
asset_dirs: [
"tests/goldens",
+ "schemas",
],
static_libs: [
"SystemUI-res",
@@ -708,6 +708,7 @@ android_library {
"androidx-constraintlayout_constraintlayout",
"androidx.exifinterface_exifinterface",
"androidx.room_room-runtime",
+ "androidx.room_room-testing",
"androidx.room_room-ktx",
"androidx.datastore_datastore-preferences",
"device_state_flags_lib",
@@ -789,7 +790,11 @@ android_library {
"android.test.mock",
"keepanno-annotations",
],
- kotlincflags: ["-Xjvm-default=all"],
+ kotlincflags: [
+ "-Xjvm-default=all",
+ // TODO(b/352363800): Why do we need this?
+ "-J-Xmx8192M",
+ ],
aaptflags: [
"--extra-packages",
"com.android.systemui",
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-bn/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-bn/strings.xml
index 9a0ebef6c639..00cc44217aed 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-bn/strings.xml
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-bn/strings.xml
@@ -23,7 +23,7 @@
<string name="accessibility_menu_description" msgid="4458354794093858297">"আপনার ডিভাইস নিয়ন্ত্রণ করতে, \'অ্যাক্সেসিবিলিটি মেনু\' একটি বড় অন-স্ক্রিন মেনু দেখায়। আপনি ফোন লক, ভলিউম ও উজ্জ্বলতা নিয়ন্ত্রণ, স্ক্রিনশট নেওয়া এবং আরও অনেক কিছু করতে পারবেন।"</string>
<string name="accessibility_menu_summary" msgid="340071398148208130">"বড় করে দেখানো মেনুর মাধ্যমে ডিভাইস নিয়ন্ত্রণ করুন"</string>
<string name="accessibility_menu_settings_name" msgid="1716888058785672611">"অ্যাক্সেসিবিলিটি মেনুর সেটিংস"</string>
- <string name="accessibility_menu_large_buttons_title" msgid="8978499601044961736">"বোতাম বড় করা"</string>
+ <string name="accessibility_menu_large_buttons_title" msgid="8978499601044961736">"বড় বোতাম"</string>
<string name="accessibility_menu_large_buttons_summary" msgid="236873938502785311">"অ্যাক্সেসিবিলিটি মেনু বোতামের সাইজ বাড়ান"</string>
<string name="pref_help_title" msgid="6871558837025010641">"সহায়তা"</string>
<string name="brightness_percentage_label" msgid="7391554573977867369">"উজ্জ্বলতা <xliff:g id="PERCENTAGE">%1$s</xliff:g> %%"</string>
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-fr-rCA/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-fr-rCA/strings.xml
index 87a95037178e..e60eac0459c5 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-fr-rCA/strings.xml
@@ -21,7 +21,7 @@
<string name="previous_button_content_description" msgid="840869171117765966">"Aller à l\'écran précédent"</string>
<string name="next_button_content_description" msgid="6810058269847364406">"Aller à l\'écran suivant"</string>
<string name="accessibility_menu_description" msgid="4458354794093858297">"Le menu Accessibilité propose un grand espace à l\'écran à l\'aide duquel vous pouvez contrôler votre appareil. Utilisez-le pour verrouiller votre appareil, régler le volume et la luminosité, prendre des captures d\'écran et plus."</string>
- <string name="accessibility_menu_summary" msgid="340071398148208130">"contrôler l\'appareil à l\'aide d\'un menu de grande taille"</string>
+ <string name="accessibility_menu_summary" msgid="340071398148208130">"Contrôle l\'appareil à l\'aide d\'un menu de grande taille"</string>
<string name="accessibility_menu_settings_name" msgid="1716888058785672611">"Paramètres du menu Accessibilité"</string>
<string name="accessibility_menu_large_buttons_title" msgid="8978499601044961736">"Boutons de grande taille"</string>
<string name="accessibility_menu_large_buttons_summary" msgid="236873938502785311">"Augmenter la taille des boutons du menu Accessibilité"</string>
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-hi/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-hi/strings.xml
index 3d59c0b62ac4..c9e8858b38a8 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-hi/strings.xml
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-hi/strings.xml
@@ -22,7 +22,7 @@
<string name="next_button_content_description" msgid="6810058269847364406">"अगली स्क्रीन पर जाएं"</string>
<string name="accessibility_menu_description" msgid="4458354794093858297">"सुलभता मेन्यू, डिवाइस की स्क्रीन पर दिखने वाला एक बड़ा मेन्यू होता है. इस मेन्यू में जाकर, डिवाइस को लॉक करने, स्क्रीनशॉट लेने, स्क्रीन की रोशनी और आवाज़ को कंट्रोल करने जैसे कई काम किए जा सकते हैं."</string>
<string name="accessibility_menu_summary" msgid="340071398148208130">"बड़े मेन्यू की मदद से डिवाइस को कंट्रोल करें"</string>
- <string name="accessibility_menu_settings_name" msgid="1716888058785672611">"सुलभता मेन्यू सेटिंग"</string>
+ <string name="accessibility_menu_settings_name" msgid="1716888058785672611">"सुलभता मेन्यू की सेटिंग"</string>
<string name="accessibility_menu_large_buttons_title" msgid="8978499601044961736">"बड़े बटन"</string>
<string name="accessibility_menu_large_buttons_summary" msgid="236873938502785311">"सुलभता मेन्यू के बटनाें का साइज़ बढ़ाएं"</string>
<string name="pref_help_title" msgid="6871558837025010641">"सहायता"</string>
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-hr/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-hr/strings.xml
index 36fcfdcd9eb3..c5388a8d6c74 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-hr/strings.xml
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-hr/strings.xml
@@ -22,9 +22,9 @@
<string name="next_button_content_description" msgid="6810058269847364406">"Idi na sljedeći zaslon"</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">"Upravljajte uređajem pomoću velikog izbornika"</string>
- <string name="accessibility_menu_settings_name" msgid="1716888058785672611">"Postavke izbornika pristupačnosti"</string>
+ <string name="accessibility_menu_settings_name" msgid="1716888058785672611">"Postavke izbornika za pristupačnost"</string>
<string name="accessibility_menu_large_buttons_title" msgid="8978499601044961736">"Veliki gumbi"</string>
- <string name="accessibility_menu_large_buttons_summary" msgid="236873938502785311">"Povećanje veličine gumba izbornika Pristupačnosti"</string>
+ <string name="accessibility_menu_large_buttons_summary" msgid="236873938502785311">"Povećaj veličinu gumba izbornika za pristupačnost"</string>
<string name="pref_help_title" msgid="6871558837025010641">"Pomoć"</string>
<string name="brightness_percentage_label" msgid="7391554573977867369">"Svjetlina <xliff:g id="PERCENTAGE">%1$s</xliff:g> %%"</string>
<string name="music_volume_percentage_label" msgid="398635599662604706">"Glasnoća glazbe <xliff:g id="PERCENTAGE">%1$s</xliff:g> %%"</string>
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-nb/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-nb/strings.xml
index 09830520dd74..e95d0edbf320 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-nb/strings.xml
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-nb/strings.xml
@@ -12,7 +12,7 @@
<string name="lockscreen_label" msgid="648347953557887087">"Låseskjerm"</string>
<string name="quick_settings_label" msgid="2999117381487601865">"Hurtiginnstillinger"</string>
<string name="notifications_label" msgid="6829741046963013567">"Varsler"</string>
- <string name="screenshot_label" msgid="863978141223970162">"Skjermdump"</string>
+ <string name="screenshot_label" msgid="863978141223970162">"Skjermbilde"</string>
<string name="screenshot_utterance" msgid="1430760563401895074">"Ta skjermbilde"</string>
<string name="volume_up_label" msgid="8592766918780362870">"Volum opp"</string>
<string name="volume_down_label" msgid="8574981863656447346">"Volum ned"</string>
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-nl/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-nl/strings.xml
index 7535c2b0f538..1e28bff6ca7e 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-nl/strings.xml
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-nl/strings.xml
@@ -24,7 +24,7 @@
<string name="accessibility_menu_summary" msgid="340071398148208130">"Bedien het apparaat via een groot menu"</string>
<string name="accessibility_menu_settings_name" msgid="1716888058785672611">"Instellingen toegankelijkheidsmenu"</string>
<string name="accessibility_menu_large_buttons_title" msgid="8978499601044961736">"Grote knoppen"</string>
- <string name="accessibility_menu_large_buttons_summary" msgid="236873938502785311">"Vergroot knoppen in het toegankelijkheidsmenu"</string>
+ <string name="accessibility_menu_large_buttons_summary" msgid="236873938502785311">"Maak knoppen in toegankelijkheidsmenu groter"</string>
<string name="pref_help_title" msgid="6871558837025010641">"Hulp"</string>
<string name="brightness_percentage_label" msgid="7391554573977867369">"Helderheid <xliff:g id="PERCENTAGE">%1$s</xliff:g>%%"</string>
<string name="music_volume_percentage_label" msgid="398635599662604706">"Muziekvolume <xliff:g id="PERCENTAGE">%1$s</xliff:g>%%"</string>
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-sk/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-sk/strings.xml
index 62f63a8739d4..3c92f83b19aa 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-sk/strings.xml
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-sk/strings.xml
@@ -22,9 +22,9 @@
<string name="next_button_content_description" msgid="6810058269847364406">"Prejsť na ďalšiu obrazovku"</string>
<string name="accessibility_menu_description" msgid="4458354794093858297">"Ponuka dostupnosti spustí na obrazovke telefónu veľkú ponuku, pomocou ktorej môžete ovládať svoje zariadenie. Môžete ho uzamknúť, ovládať hlasitosť a jas, vytvárať snímky obrazovky a mnoho ďalšieho."</string>
<string name="accessibility_menu_summary" msgid="340071398148208130">"Ovládanie zariadenia pomocou veľkej ponuky"</string>
- <string name="accessibility_menu_settings_name" msgid="1716888058785672611">"Nastavenia ponuky dostupnosti"</string>
+ <string name="accessibility_menu_settings_name" msgid="1716888058785672611">"Nastavenia ponuky Dostupnosť"</string>
<string name="accessibility_menu_large_buttons_title" msgid="8978499601044961736">"Veľké tlačidlá"</string>
- <string name="accessibility_menu_large_buttons_summary" msgid="236873938502785311">"Zväčšiť tlačidlá ponuky dostupnosti"</string>
+ <string name="accessibility_menu_large_buttons_summary" msgid="236873938502785311">"Zväčšiť tlačidlá ponuky Dostupnosť"</string>
<string name="pref_help_title" msgid="6871558837025010641">"Pomocník"</string>
<string name="brightness_percentage_label" msgid="7391554573977867369">"Jas: <xliff:g id="PERCENTAGE">%1$s</xliff:g> %%"</string>
<string name="music_volume_percentage_label" msgid="398635599662604706">"Hlasitosť hudby: <xliff:g id="PERCENTAGE">%1$s</xliff:g> %%"</string>
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index a1f1a08d4bf2..71f5511af4f5 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -591,10 +591,13 @@ flag {
}
flag {
- name: "screenshot_shelf_ui2"
+ name: "screenshot_save_image_exporter"
namespace: "systemui"
- description: "Use new shelf UI flow for screenshots"
- bug: "329659738"
+ description: "Save all screenshots using ImageExporter"
+ bug: "352308052"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
}
flag {
@@ -1150,3 +1153,37 @@ flag {
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ namespace: "systemui"
+ name: "qs_register_setting_observer_on_bg_thread"
+ description: "Registers Quick Settings content providers on background thread"
+ bug: "351766769"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
+ name: "sounddose_customization"
+ namespace: "systemui"
+ description: "Enables custom actions for sounddose notifications"
+ bug: "345227709"
+}
+
+flag {
+ namespace: "systemui"
+ name: "register_content_observers_async"
+ description: "Use new Async API to register content observers"
+ bug: "316922634"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
+ name: "msdl_feedback"
+ namespace: "systemui"
+ description: "Enables MSDL feedback in SysUI surfaces."
+ bug: "352600066"
+} \ No newline at end of file
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt
index b8f9ca82f072..f655ac1d207b 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt
@@ -83,6 +83,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.PlatformButton
import com.android.compose.animation.Easings
import com.android.compose.animation.scene.ElementKey
+import com.android.compose.animation.scene.MutableSceneTransitionLayoutState
import com.android.compose.animation.scene.SceneKey
import com.android.compose.animation.scene.SceneScope
import com.android.compose.animation.scene.SceneTransitionLayout
@@ -516,13 +517,22 @@ private fun FoldAware(
val currentSceneKey =
if (isSplitAroundTheFold) SceneKeys.SplitSceneKey else SceneKeys.ContiguousSceneKey
- SceneTransitionLayout(
- currentScene = currentSceneKey,
- onChangeScene = {},
- transitions = SceneTransitions,
- modifier = modifier,
- enableInterruptions = false,
- ) {
+ val state = remember {
+ MutableSceneTransitionLayoutState(
+ currentSceneKey,
+ SceneTransitions,
+ enableInterruptions = false,
+ )
+ }
+
+ // Update state whenever currentSceneKey has changed.
+ LaunchedEffect(state, currentSceneKey) {
+ if (currentSceneKey != state.transitionState.currentScene) {
+ state.setTargetScene(currentSceneKey, coroutineScope = this)
+ }
+ }
+
+ SceneTransitionLayout(state, modifier = modifier) {
scene(SceneKeys.ContiguousSceneKey) {
FoldableScene(
aboveFold = aboveFold,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
index f6535ec0b710..8f247f60bfc4 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
@@ -94,6 +94,7 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
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
@@ -171,7 +172,11 @@ fun CommunalHub(
var removeButtonCoordinates: LayoutCoordinates? by remember { mutableStateOf(null) }
var toolbarSize: IntSize? by remember { mutableStateOf(null) }
var gridCoordinates: LayoutCoordinates? by remember { mutableStateOf(null) }
- val gridState = rememberLazyGridState()
+
+ val gridState =
+ rememberLazyGridState(viewModel.savedFirstScrollIndex, viewModel.savedFirstScrollOffset)
+ viewModel.clearPersistedScrollPosition()
+
val contentListState = rememberContentListState(widgetConfigurator, communalContent, viewModel)
val reorderingWidgets by viewModel.reorderingWidgets.collectAsStateWithLifecycle()
val selectedKey = viewModel.selectedKey.collectAsStateWithLifecycle()
@@ -187,6 +192,8 @@ fun CommunalHub(
val contentPadding = gridContentPadding(viewModel.isEditMode, toolbarSize)
val contentOffset = beforeContentPadding(contentPadding).toOffset()
+ ObserveScrollEffect(gridState, viewModel)
+
if (!viewModel.isEditMode) {
ScrollOnUpdatedLiveContentEffect(communalContent, gridState)
}
@@ -420,6 +427,20 @@ private fun DisclaimerBottomSheetContent(onButtonClicked: () -> Unit) {
}
}
+@Composable
+private fun ObserveScrollEffect(
+ gridState: LazyGridState,
+ communalViewModel: BaseCommunalViewModel
+) {
+
+ LaunchedEffect(gridState) {
+ snapshotFlow {
+ Pair(gridState.firstVisibleItemIndex, gridState.firstVisibleItemScrollOffset)
+ }
+ .collect { communalViewModel.onScrollPositionUpdated(it.first, it.second) }
+ }
+}
+
/**
* Observes communal content and scrolls to any added or updated live content, e.g. a new media
* session is started, or a paused timer is resumed.
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt
index 0a4c6fd21922..7400711e36df 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt
@@ -67,8 +67,7 @@ constructor(
@Composable
override fun SceneScope.Content(modifier: Modifier) {
val isUdfpsVisible = viewModel.isUdfpsVisible
- val shouldUseSplitNotificationShade by
- viewModel.shouldUseSplitNotificationShade.collectAsStateWithLifecycle()
+ val isShadeLayoutWide by viewModel.isShadeLayoutWide.collectAsStateWithLifecycle()
val unfoldTranslations by viewModel.unfoldTranslations.collectAsStateWithLifecycle()
LockscreenLongPress(
@@ -100,7 +99,7 @@ constructor(
}
)
}
- if (shouldUseSplitNotificationShade) {
+ if (isShadeLayoutWide) {
with(notificationSection) {
Notifications(
burnInParams = null,
@@ -112,7 +111,7 @@ constructor(
}
}
}
- if (!shouldUseSplitNotificationShade) {
+ if (!isShadeLayoutWide) {
with(notificationSection) {
Notifications(
burnInParams = null,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ShortcutsBesideUdfpsBlueprint.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ShortcutsBesideUdfpsBlueprint.kt
index 065f2a2172b1..72cf83269760 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ShortcutsBesideUdfpsBlueprint.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ShortcutsBesideUdfpsBlueprint.kt
@@ -69,8 +69,7 @@ constructor(
@Composable
override fun SceneScope.Content(modifier: Modifier) {
val isUdfpsVisible = viewModel.isUdfpsVisible
- val shouldUseSplitNotificationShade by
- viewModel.shouldUseSplitNotificationShade.collectAsStateWithLifecycle()
+ val isShadeLayoutWide by viewModel.isShadeLayoutWide.collectAsStateWithLifecycle()
val unfoldTranslations by viewModel.unfoldTranslations.collectAsStateWithLifecycle()
LockscreenLongPress(
@@ -102,7 +101,7 @@ constructor(
},
)
}
- if (shouldUseSplitNotificationShade) {
+ if (isShadeLayoutWide) {
with(notificationSection) {
Notifications(
burnInParams = null,
@@ -114,7 +113,7 @@ constructor(
}
}
}
- if (!shouldUseSplitNotificationShade) {
+ if (!isShadeLayoutWide) {
with(notificationSection) {
Notifications(
burnInParams = null,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/NotificationSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/NotificationSection.kt
index 7f80dfa703bc..a1f20423ad3b 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/NotificationSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/NotificationSection.kt
@@ -90,8 +90,8 @@ constructor(
*/
@Composable
fun SceneScope.Notifications(burnInParams: BurnInParameters?, modifier: Modifier = Modifier) {
- val shouldUseSplitNotificationShade by
- lockscreenContentViewModel.shouldUseSplitNotificationShade.collectAsStateWithLifecycle()
+ val isShadeLayoutWide by
+ lockscreenContentViewModel.isShadeLayoutWide.collectAsStateWithLifecycle()
val areNotificationsVisible by
lockscreenContentViewModel.areNotificationsVisible.collectAsStateWithLifecycle()
val splitShadeTopMargin: Dp =
@@ -111,9 +111,7 @@ constructor(
modifier =
modifier
.fillMaxWidth()
- .thenIf(shouldUseSplitNotificationShade) {
- Modifier.padding(top = splitShadeTopMargin)
- }
+ .thenIf(isShadeLayoutWide) { Modifier.padding(top = splitShadeTopMargin) }
.let {
if (burnInParams == null) {
it
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/StatusBarSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/StatusBarSection.kt
index 166aa70c1d4a..f9e22525237b 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/StatusBarSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/StatusBarSection.kt
@@ -28,7 +28,6 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
-import com.android.compose.animation.scene.ElementKey
import com.android.compose.animation.scene.SceneScope
import com.android.compose.modifiers.height
import com.android.keyguard.dagger.KeyguardStatusBarViewComponent
@@ -83,29 +82,20 @@ constructor(
componentFactory.build(view, provider).keyguardStatusBarViewController
}
- MovableElement(
- key = StatusBarElementKey,
- modifier = modifier,
- ) {
- content {
- AndroidView(
- factory = {
- notificationPanelView.get().findViewById<View>(R.id.keyguard_header)?.let {
- (it.parent as ViewGroup).removeView(it)
- }
+ AndroidView(
+ factory = {
+ notificationPanelView.get().findViewById<View>(R.id.keyguard_header)?.let {
+ (it.parent as ViewGroup).removeView(it)
+ }
- viewController.init()
- view
- },
- modifier =
- Modifier.fillMaxWidth().padding(horizontal = 16.dp).height {
- Utils.getStatusBarHeaderHeightKeyguard(context)
- },
- update = { viewController.setDisplayCutout(viewDisplayCutout) }
- )
- }
- }
+ viewController.init()
+ view
+ },
+ modifier =
+ Modifier.fillMaxWidth().padding(horizontal = 16.dp).height {
+ Utils.getStatusBarHeaderHeightKeyguard(context)
+ },
+ update = { viewController.setDisplayCutout(viewDisplayCutout) }
+ )
}
}
-
-private val StatusBarElementKey = ElementKey("StatusBar")
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt
index 067315381773..0cd4b6816a61 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt
@@ -26,6 +26,7 @@ import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
+import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
@@ -33,6 +34,7 @@ import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.IntOffset
import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import com.android.compose.animation.scene.MutableSceneTransitionLayoutState
import com.android.compose.animation.scene.SceneScope
import com.android.compose.animation.scene.SceneTransitionLayout
import com.android.compose.modifiers.thenIf
@@ -78,13 +80,22 @@ constructor(
WeatherClockScenes.splitShadeLargeClockScene
}
- SceneTransitionLayout(
- modifier = modifier,
- currentScene = currentScene,
- onChangeScene = {},
- transitions = ClockTransition.defaultClockTransitions,
- enableInterruptions = false,
- ) {
+ val state = remember {
+ MutableSceneTransitionLayoutState(
+ currentScene,
+ ClockTransition.defaultClockTransitions,
+ enableInterruptions = false,
+ )
+ }
+
+ // Update state whenever currentSceneKey has changed.
+ LaunchedEffect(state, currentScene) {
+ if (currentScene != state.transitionState.currentScene) {
+ state.setTargetScene(currentScene, coroutineScope = this)
+ }
+ }
+
+ SceneTransitionLayout(state, modifier) {
scene(splitShadeLargeClockScene) {
LargeClockWithSmartSpace(
shouldOffSetClockToOneHalf = !hasCustomPositionUpdatedAnimation
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaCarousel.kt b/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaCarousel.kt
index 581f3a5cacff..d629eec1c45a 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaCarousel.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaCarousel.kt
@@ -16,8 +16,10 @@
package com.android.systemui.media.controls.ui.composable
+import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
+import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.runtime.Composable
@@ -26,7 +28,6 @@ import androidx.compose.ui.layout.layout
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.viewinterop.AndroidView
-import androidx.core.view.contains
import com.android.compose.animation.scene.ElementKey
import com.android.compose.animation.scene.SceneScope
import com.android.systemui.media.controls.ui.controller.MediaCarouselController
@@ -36,7 +37,8 @@ import com.android.systemui.util.animation.MeasurementInput
private object MediaCarousel {
object Elements {
- internal val Content = ElementKey("MediaCarouselContent")
+ internal val Content =
+ ElementKey(debugName = "MediaCarouselContent", scenePicker = MediaScenePicker)
}
}
@@ -61,40 +63,43 @@ fun SceneScope.MediaCarousel(
mediaHost.measurementInput = MeasurementInput(layoutWidth, layoutHeight)
carouselController.setSceneContainerSize(layoutWidth, layoutHeight)
- AndroidView(
- modifier =
- modifier
- .element(MediaCarousel.Elements.Content)
- .height(mediaHeight)
- .fillMaxWidth()
- .layout { measurable, constraints ->
- val placeable = measurable.measure(constraints)
+ MovableElement(
+ key = MediaCarousel.Elements.Content,
+ modifier = modifier.height(mediaHeight).fillMaxWidth()
+ ) {
+ content {
+ AndroidView(
+ modifier =
+ Modifier.fillMaxSize().layout { measurable, constraints ->
+ val placeable = measurable.measure(constraints)
- // Notify controller to size the carousel for the current space
- mediaHost.measurementInput = MeasurementInput(placeable.width, placeable.height)
- carouselController.setSceneContainerSize(placeable.width, placeable.height)
+ // Notify controller to size the carousel for the current space
+ mediaHost.measurementInput =
+ MeasurementInput(placeable.width, placeable.height)
+ carouselController.setSceneContainerSize(placeable.width, placeable.height)
- layout(placeable.width, placeable.height) { placeable.placeRelative(0, 0) }
+ layout(placeable.width, placeable.height) { placeable.placeRelative(0, 0) }
+ },
+ factory = { context ->
+ FrameLayout(context).apply {
+ layoutParams =
+ FrameLayout.LayoutParams(
+ FrameLayout.LayoutParams.MATCH_PARENT,
+ FrameLayout.LayoutParams.MATCH_PARENT,
+ )
+ }
},
- factory = { context ->
- FrameLayout(context).apply {
- val mediaFrame = carouselController.mediaFrame
- (mediaFrame.parent as? ViewGroup)?.removeView(mediaFrame)
- addView(mediaFrame)
- layoutParams =
- FrameLayout.LayoutParams(
- FrameLayout.LayoutParams.MATCH_PARENT,
- FrameLayout.LayoutParams.MATCH_PARENT,
- )
- }
- },
- update = {
- if (it.contains(carouselController.mediaFrame)) {
- return@AndroidView
- }
- val mediaFrame = carouselController.mediaFrame
- (mediaFrame.parent as? ViewGroup)?.removeView(mediaFrame)
- it.addView(mediaFrame)
- },
- )
+ update = { it.setView(carouselController.mediaFrame) },
+ onRelease = { it.removeAllViews() }
+ )
+ }
+ }
+}
+
+private fun ViewGroup.setView(view: View) {
+ if (view.parent == this) {
+ return
+ }
+ (view.parent as? ViewGroup)?.removeView(view)
+ addView(view)
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaScenePicker.kt b/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaScenePicker.kt
new file mode 100644
index 000000000000..039813390f1e
--- /dev/null
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaScenePicker.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.media.controls.ui.composable
+
+import com.android.compose.animation.scene.ElementKey
+import com.android.compose.animation.scene.ElementScenePicker
+import com.android.compose.animation.scene.SceneKey
+import com.android.compose.animation.scene.TransitionState
+import com.android.systemui.scene.shared.model.Scenes
+
+/** [ElementScenePicker] implementation for the media carousel object. */
+object MediaScenePicker : ElementScenePicker {
+
+ private val shadeLockscreenFraction = 0.65f
+ private val scenes =
+ setOf(
+ Scenes.Lockscreen,
+ Scenes.Shade,
+ Scenes.QuickSettings,
+ Scenes.QuickSettingsShade,
+ Scenes.Communal
+ )
+
+ override fun sceneDuringTransition(
+ element: ElementKey,
+ transition: TransitionState.Transition,
+ fromSceneZIndex: Float,
+ toSceneZIndex: Float
+ ): SceneKey? {
+ return when {
+ // TODO: 352052894 - update with the actual scene picking
+ transition.isTransitioning(from = Scenes.Lockscreen, to = Scenes.Shade) -> {
+ if (transition.progress < shadeLockscreenFraction) {
+ Scenes.Lockscreen
+ } else {
+ Scenes.Shade
+ }
+ }
+
+ // TODO: 345467290 - update with the actual scene picking
+ transition.isTransitioning(from = Scenes.Shade, to = Scenes.Lockscreen) -> {
+ if (transition.progress < 1f - shadeLockscreenFraction) {
+ Scenes.Shade
+ } else {
+ Scenes.Lockscreen
+ }
+ }
+
+ // TODO: 345467290 - update with the actual scene picking
+ transition.isTransitioningBetween(Scenes.QuickSettings, Scenes.Shade) -> {
+ Scenes.QuickSettings
+ }
+
+ // TODO: 340216785 - update with the actual scene picking
+ else -> pickSingleSceneIn(scenes, transition, element)
+ }
+ }
+}
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 4a6599a04fab..805351ea8bbe 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
@@ -34,9 +34,11 @@ import androidx.compose.foundation.layout.displayCutoutPadding
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.navigationBars
import androidx.compose.foundation.layout.navigationBarsPadding
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
@@ -51,6 +53,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.CompositingStrategy
import androidx.compose.ui.graphics.graphicsLayer
+import androidx.compose.ui.input.pointer.pointerInteropFilter
import androidx.compose.ui.layout.Layout
import androidx.compose.ui.layout.layoutId
import androidx.compose.ui.platform.LocalDensity
@@ -60,6 +63,7 @@ import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.animation.scene.ElementKey
import com.android.compose.animation.scene.LowestZIndexScenePicker
+import com.android.compose.animation.scene.NestedScrollBehavior
import com.android.compose.animation.scene.SceneScope
import com.android.compose.animation.scene.TransitionState
import com.android.compose.animation.scene.UserAction
@@ -255,6 +259,8 @@ private fun SceneScope.SingleShade(
val mediaOffset by
animateSceneDpAsState(value = InQQS, key = MediaLandscapeTopOffset, canOverflow = false)
+ val navBarHeight = WindowInsets.systemBars.asPaddingValues().calculateBottomPadding()
+
Box(
modifier =
modifier.thenIf(shouldPunchHoleBehindScrim) {
@@ -358,11 +364,22 @@ private fun SceneScope.SingleShade(
notificationsPlaceable.placeRelative(x = 0, y = maxNotifScrimTop.value.roundToInt())
}
}
- NotificationStackCutoffGuideline(
- stackScrollView = notificationStackScrollView,
- viewModel = notificationsPlaceholderViewModel,
- modifier = Modifier.align(Alignment.BottomCenter).navigationBarsPadding()
- )
+ Box(
+ modifier =
+ Modifier.align(Alignment.BottomCenter)
+ .height(navBarHeight)
+ .pointerInteropFilter { true }
+ .verticalNestedScrollToScene(
+ topBehavior = NestedScrollBehavior.EdgeAlways,
+ isExternalOverscrollGesture = { false }
+ )
+ ) {
+ NotificationStackCutoffGuideline(
+ stackScrollView = notificationStackScrollView,
+ viewModel = notificationsPlaceholderViewModel,
+ modifier = Modifier.align(Alignment.TopCenter)
+ )
+ }
}
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/statusbar/ui/composable/StatusBar.kt b/packages/SystemUI/compose/features/src/com/android/systemui/statusbar/ui/composable/StatusBar.kt
deleted file mode 100644
index f514ab4a710b..000000000000
--- a/packages/SystemUI/compose/features/src/com/android/systemui/statusbar/ui/composable/StatusBar.kt
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package com.android.systemui.statusbar.ui.composable
-
-import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.defaultMinSize
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.padding
-import androidx.compose.material3.Text
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.unit.dp
-
-@Composable
-fun StatusBar(
- modifier: Modifier = Modifier,
-) {
- // TODO(b/272780101): implement.
- Row(
- modifier = modifier.fillMaxWidth().defaultMinSize(minHeight = 48.dp).padding(4.dp),
- horizontalArrangement = Arrangement.Center,
- verticalAlignment = Alignment.CenterVertically,
- ) {
- Text("Status bar")
- }
-}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt
index cdcfc84ce92a..615d393f8bee 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt
@@ -241,43 +241,50 @@ internal class MultiPointerDraggableNode(
}
}
- awaitPointerEventScope {
- while (isActive) {
- try {
- detectDragGestures(
- orientation = orientation,
- startDragImmediately = startDragImmediately,
- onDragStart = { startedPosition, overSlop, pointersDown ->
- velocityTracker.resetTracking()
- onDragStarted(startedPosition, overSlop, pointersDown)
- },
- onDrag = { controller, change, amount ->
- velocityTracker.addPointerInputChange(change)
- controller.onDrag(amount)
- },
- onDragEnd = { controller ->
- val viewConfiguration = currentValueOf(LocalViewConfiguration)
- val maxVelocity =
- viewConfiguration.maximumFlingVelocity.let { Velocity(it, it) }
- val velocity = velocityTracker.calculateVelocity(maxVelocity)
- controller.onStop(
- velocity =
- when (orientation) {
- Orientation.Horizontal -> velocity.x
- Orientation.Vertical -> velocity.y
- },
- canChangeScene = true,
- )
- },
- onDragCancel = { controller ->
- controller.onStop(velocity = 0f, canChangeScene = true)
- },
- swipeDetector = swipeDetector
- )
- } catch (exception: CancellationException) {
- // If the coroutine scope is active, we can just restart the drag cycle.
- if (!isActive) {
- throw exception
+ // The order is important here: we want to make sure that the previous PointerEventScope
+ // is initialized first. This ensures that the following PointerEventScope doesn't
+ // receive more events than the first one.
+ launch {
+ awaitPointerEventScope {
+ while (isActive) {
+ try {
+ detectDragGestures(
+ orientation = orientation,
+ startDragImmediately = startDragImmediately,
+ onDragStart = { startedPosition, overSlop, pointersDown ->
+ velocityTracker.resetTracking()
+ onDragStarted(startedPosition, overSlop, pointersDown)
+ },
+ onDrag = { controller, change, amount ->
+ velocityTracker.addPointerInputChange(change)
+ controller.onDrag(amount)
+ },
+ onDragEnd = { controller ->
+ val viewConfiguration = currentValueOf(LocalViewConfiguration)
+ val maxVelocity =
+ viewConfiguration.maximumFlingVelocity.let {
+ Velocity(it, it)
+ }
+ val velocity = velocityTracker.calculateVelocity(maxVelocity)
+ controller.onStop(
+ velocity =
+ when (orientation) {
+ Orientation.Horizontal -> velocity.x
+ Orientation.Vertical -> velocity.y
+ },
+ canChangeScene = true,
+ )
+ },
+ onDragCancel = { controller ->
+ controller.onStop(velocity = 0f, canChangeScene = true)
+ },
+ swipeDetector = swipeDetector
+ )
+ } catch (exception: CancellationException) {
+ // If the coroutine scope is active, we can just restart the drag cycle.
+ if (!isActive) {
+ throw exception
+ }
}
}
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/PredictiveBackHandler.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/PredictiveBackHandler.kt
index dfb8c499b4c9..734241e2faf6 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/PredictiveBackHandler.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/PredictiveBackHandler.kt
@@ -56,13 +56,7 @@ internal fun PredictiveBackHandler(
progress.collect { backEvent -> transition.dragProgress = backEvent.progress }
// Back gesture successful.
- transition.animateTo(
- if (state.canChangeScene(targetSceneForBack)) {
- targetSceneForBack
- } else {
- fromScene
- }
- )
+ transition.animateTo(targetSceneForBack)
} catch (e: CancellationException) {
// Back gesture cancelled.
transition.animateTo(fromScene)
@@ -105,12 +99,15 @@ private class PredictiveBackTransition(
return it
}
- currentScene = scene
+ if (scene != currentScene && state.transitionState == this && state.canChangeScene(scene)) {
+ currentScene = scene
+ }
+
val targetProgress =
- when (scene) {
+ when (currentScene) {
fromScene -> 0f
toScene -> 1f
- else -> error("scene $scene should be either $fromScene or $toScene")
+ else -> error("scene $currentScene should be either $fromScene or $toScene")
}
val animatable = Animatable(dragProgress).also { progressAnimatable = it }
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/PunchHole.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/PunchHole.kt
deleted file mode 100644
index b346a70e61f9..000000000000
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/PunchHole.kt
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.compose.animation.scene
-
-import androidx.compose.runtime.Stable
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.geometry.Offset
-import androidx.compose.ui.geometry.Size
-import androidx.compose.ui.graphics.BlendMode
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.graphics.CompositingStrategy
-import androidx.compose.ui.graphics.Outline
-import androidx.compose.ui.graphics.RectangleShape
-import androidx.compose.ui.graphics.Shape
-import androidx.compose.ui.graphics.drawOutline
-import androidx.compose.ui.graphics.drawscope.ContentDrawScope
-import androidx.compose.ui.graphics.drawscope.DrawScope
-import androidx.compose.ui.graphics.drawscope.translate
-import androidx.compose.ui.layout.LayoutCoordinates
-import androidx.compose.ui.layout.Measurable
-import androidx.compose.ui.layout.MeasureResult
-import androidx.compose.ui.layout.MeasureScope
-import androidx.compose.ui.node.DelegatingNode
-import androidx.compose.ui.node.DrawModifierNode
-import androidx.compose.ui.node.GlobalPositionAwareModifierNode
-import androidx.compose.ui.node.LayoutModifierNode
-import androidx.compose.ui.node.ModifierNodeElement
-import androidx.compose.ui.unit.Constraints
-import androidx.compose.ui.unit.LayoutDirection
-import androidx.compose.ui.unit.toSize
-
-/**
- * Punch a hole in this node with the given [size], [offset] and [shape].
- *
- * Punching a hole in an element will "remove" any pixel drawn by that element in the hole area.
- * This can be used to make content drawn below an opaque element visible. For example, if we have
- * [this lockscreen scene](http://shortn/_VYySFnJDhN) drawn below
- * [this shade scene](http://shortn/_fpxGUk0Rg7) and punch a hole in the latter using the big clock
- * time bounds and a RoundedCornerShape(10dp), [this](http://shortn/_qt80IvORFj) would be the
- * result.
- */
-@Stable
-fun Modifier.punchHole(
- size: () -> Size,
- offset: () -> Offset,
- shape: Shape = RectangleShape,
-): Modifier = this.then(PunchHoleElement(size, offset, shape))
-
-/**
- * Punch a hole in this node using the bounds of [coords] and the given [shape].
- *
- * You can use [androidx.compose.ui.layout.onGloballyPositioned] to get the last coordinates of a
- * node.
- */
-@Stable
-fun Modifier.punchHole(
- coords: () -> LayoutCoordinates?,
- shape: Shape = RectangleShape,
-): Modifier = this.then(PunchHoleWithBoundsElement(coords, shape))
-
-private data class PunchHoleElement(
- private val size: () -> Size,
- private val offset: () -> Offset,
- private val shape: Shape,
-) : ModifierNodeElement<PunchHoleNode>() {
- override fun create(): PunchHoleNode = PunchHoleNode(size, offset, { shape })
-
- override fun update(node: PunchHoleNode) {
- node.size = size
- node.offset = offset
- node.shape = { shape }
- }
-}
-
-private class PunchHoleNode(
- var size: () -> Size,
- var offset: () -> Offset,
- var shape: () -> Shape,
-) : Modifier.Node(), DrawModifierNode, LayoutModifierNode {
- private var lastSize: Size = Size.Unspecified
- private var lastLayoutDirection: LayoutDirection = LayoutDirection.Ltr
- private var lastOutline: Outline? = null
-
- override fun MeasureScope.measure(
- measurable: Measurable,
- constraints: Constraints
- ): MeasureResult {
- return measurable.measure(constraints).run {
- layout(width, height) {
- placeWithLayer(0, 0) { compositingStrategy = CompositingStrategy.Offscreen }
- }
- }
- }
-
- override fun ContentDrawScope.draw() {
- drawContent()
-
- val holeSize = size()
- if (holeSize != Size.Zero) {
- val offset = offset()
- translate(offset.x, offset.y) { drawHole(holeSize) }
- }
- }
-
- private fun DrawScope.drawHole(size: Size) {
- if (shape == RectangleShape) {
- drawRect(Color.Black, size = size, blendMode = BlendMode.DstOut)
- return
- }
-
- val outline =
- if (size == lastSize && layoutDirection == lastLayoutDirection) {
- lastOutline!!
- } else {
- val newOutline = shape().createOutline(size, layoutDirection, this)
- lastSize = size
- lastLayoutDirection = layoutDirection
- lastOutline = newOutline
- newOutline
- }
-
- drawOutline(
- outline,
- Color.Black,
- blendMode = BlendMode.DstOut,
- )
- }
-}
-
-private data class PunchHoleWithBoundsElement(
- private val coords: () -> LayoutCoordinates?,
- private val shape: Shape,
-) : ModifierNodeElement<PunchHoleWithBoundsNode>() {
- override fun create(): PunchHoleWithBoundsNode = PunchHoleWithBoundsNode(coords, shape)
-
- override fun update(node: PunchHoleWithBoundsNode) {
- node.holeCoords = coords
- node.shape = shape
- }
-}
-
-private class PunchHoleWithBoundsNode(
- var holeCoords: () -> LayoutCoordinates?,
- var shape: Shape,
-) : DelegatingNode(), DrawModifierNode, GlobalPositionAwareModifierNode {
- private val delegate = delegate(PunchHoleNode(::holeSize, ::holeOffset, ::shape))
- private var lastCoords: LayoutCoordinates? = null
-
- override fun onGloballyPositioned(coordinates: LayoutCoordinates) {
- this.lastCoords = coordinates
- }
-
- override fun ContentDrawScope.draw() = with(delegate) { draw() }
-
- private fun holeSize(): Size {
- return holeCoords()?.size?.toSize() ?: Size.Zero
- }
-
- private fun holeOffset(): Offset {
- val holeCoords = holeCoords() ?: return Offset.Zero
- val lastCoords = lastCoords ?: error("draw() was called before onGloballyPositioned()")
- return lastCoords.localPositionOf(holeCoords, relativeToSource = Offset.Zero)
- }
-}
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 7c8fce8f297d..45758c53d69a 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
@@ -48,7 +48,6 @@ import androidx.compose.ui.unit.IntSize
* @param transitionInterceptionThreshold used during a scene transition. For the scene to be
* intercepted, the progress value must be above the threshold, and below (1 - threshold).
* @param scenes the configuration of the different scenes of this layout.
- * @see updateSceneTransitionLayoutState
*/
@Composable
fun SceneTransitionLayout(
@@ -70,56 +69,6 @@ fun SceneTransitionLayout(
)
}
-/**
- * [SceneTransitionLayout] is a container that automatically animates its content whenever
- * [currentScene] changes, using the transitions defined in [transitions].
- *
- * Note: You should use [androidx.compose.animation.AnimatedContent] instead of
- * [SceneTransitionLayout] if it fits your need. Use [SceneTransitionLayout] over AnimatedContent if
- * you need support for swipe gestures, shared elements or transitions defined declaratively outside
- * UI code.
- *
- * @param currentScene the current scene
- * @param onChangeScene a mutator that should set [currentScene] to the given scene when called.
- * This is called when the user commits a transition to a new scene because of a [UserAction], for
- * instance by triggering back navigation or by swiping to a new scene.
- * @param transitions the definition of the transitions used to animate a change of scene.
- * @param swipeSourceDetector the source detector used to detect which source a swipe is started
- * from, if any.
- * @param transitionInterceptionThreshold used during a scene transition. For the scene to be
- * intercepted, the progress value must be above the threshold, and below (1 - threshold).
- * @param scenes the configuration of the different scenes of this layout.
- */
-@Composable
-fun SceneTransitionLayout(
- currentScene: SceneKey,
- onChangeScene: (SceneKey) -> Unit,
- transitions: SceneTransitions,
- modifier: Modifier = Modifier,
- swipeSourceDetector: SwipeSourceDetector = DefaultEdgeDetector,
- swipeDetector: SwipeDetector = DefaultSwipeDetector,
- @FloatRange(from = 0.0, to = 0.5) transitionInterceptionThreshold: Float = 0f,
- enableInterruptions: Boolean = DEFAULT_INTERRUPTIONS_ENABLED,
- scenes: SceneTransitionLayoutScope.() -> Unit,
-) {
- val state =
- updateSceneTransitionLayoutState(
- currentScene,
- onChangeScene,
- transitions,
- enableInterruptions = enableInterruptions,
- )
-
- SceneTransitionLayout(
- state,
- modifier,
- swipeSourceDetector,
- swipeDetector,
- transitionInterceptionThreshold,
- scenes,
- )
-}
-
interface SceneTransitionLayoutScope {
/**
* Add a scene to this layout, identified by [key].
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 5b4fbf036083..56c8752eb53c 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
@@ -22,13 +22,9 @@ import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.AnimationVector1D
import androidx.compose.animation.core.spring
import androidx.compose.foundation.gestures.Orientation
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.Stable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.util.fastAll
import androidx.compose.ui.util.fastFilter
@@ -38,14 +34,12 @@ import com.android.compose.animation.scene.transition.link.StateLink
import kotlin.math.absoluteValue
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
-import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.launch
/**
* The state of a [SceneTransitionLayout].
*
* @see MutableSceneTransitionLayoutState
- * @see updateSceneTransitionLayoutState
*/
@Stable
sealed interface SceneTransitionLayoutState {
@@ -152,55 +146,6 @@ fun MutableSceneTransitionLayoutState(
)
}
-/**
- * Sets up a [SceneTransitionLayoutState] and keeps it synced with [currentScene], [onChangeScene]
- * and [transitions]. New transitions will automatically be started whenever [currentScene] is
- * changed.
- *
- * @param currentScene the current scene
- * @param onChangeScene a mutator that should set [currentScene] to the given scene when called.
- * This is called when the user commits a transition to a new scene because of a [UserAction], for
- * instance by triggering back navigation or by swiping to a new scene.
- * @param transitions the definition of the transitions used to animate a change of scene.
- * @param canChangeScene whether we can transition to the given scene. This is called when the user
- * commits a transition to a new scene because of a [UserAction]. If [canChangeScene] returns
- * `true`, then [onChangeScene] will be called right afterwards with the same [SceneKey]. If it
- * returns `false`, the user action will be cancelled and we will animate back to the current
- * scene.
- * @param stateLinks the [StateLink] connecting this [SceneTransitionLayoutState] to other
- * [SceneTransitionLayoutState]s.
- */
-@Composable
-fun updateSceneTransitionLayoutState(
- currentScene: SceneKey,
- onChangeScene: (SceneKey) -> Unit,
- transitions: SceneTransitions = SceneTransitions.Empty,
- canChangeScene: (SceneKey) -> Boolean = { true },
- stateLinks: List<StateLink> = emptyList(),
- enableInterruptions: Boolean = DEFAULT_INTERRUPTIONS_ENABLED,
-): SceneTransitionLayoutState {
- return remember {
- HoistedSceneTransitionLayoutState(
- currentScene,
- transitions,
- onChangeScene,
- canChangeScene,
- stateLinks,
- enableInterruptions,
- )
- }
- .apply {
- update(
- currentScene,
- onChangeScene,
- canChangeScene,
- transitions,
- stateLinks,
- enableInterruptions,
- )
- }
-}
-
@Stable
sealed interface TransitionState {
/**
@@ -729,58 +674,6 @@ internal abstract class BaseSceneTransitionLayoutState(
}
}
-/**
- * A [SceneTransitionLayout] whose current scene/source of truth is hoisted (its current value comes
- * from outside).
- */
-internal class HoistedSceneTransitionLayoutState(
- initialScene: SceneKey,
- override var transitions: SceneTransitions,
- private var changeScene: (SceneKey) -> Unit,
- private var canChangeScene: (SceneKey) -> Boolean,
- stateLinks: List<StateLink> = emptyList(),
- enableInterruptions: Boolean = DEFAULT_INTERRUPTIONS_ENABLED,
-) : BaseSceneTransitionLayoutState(initialScene, stateLinks, enableInterruptions) {
- private val targetSceneChannel = Channel<SceneKey>(Channel.CONFLATED)
-
- override fun canChangeScene(scene: SceneKey): Boolean = canChangeScene.invoke(scene)
-
- override fun CoroutineScope.onChangeScene(scene: SceneKey) = changeScene.invoke(scene)
-
- @Composable
- fun update(
- currentScene: SceneKey,
- onChangeScene: (SceneKey) -> Unit,
- canChangeScene: (SceneKey) -> Boolean,
- transitions: SceneTransitions,
- stateLinks: List<StateLink>,
- enableInterruptions: Boolean,
- ) {
- SideEffect {
- this.changeScene = onChangeScene
- this.canChangeScene = canChangeScene
- this.transitions = transitions
- this.stateLinks = stateLinks
- this.enableInterruptions = enableInterruptions
-
- targetSceneChannel.trySend(currentScene)
- }
-
- LaunchedEffect(targetSceneChannel) {
- for (newKey in targetSceneChannel) {
- // Inspired by AnimateAsState.kt: let's poll the last value to avoid being one frame
- // late.
- val newKey = targetSceneChannel.tryReceive().getOrNull() ?: newKey
- animateToScene(
- layoutState = this@HoistedSceneTransitionLayoutState,
- target = newKey,
- transitionKey = null,
- )
- }
- }
- }
-}
-
/** A [MutableSceneTransitionLayoutState] that holds the value for the current scene. */
internal class MutableSceneTransitionLayoutStateImpl(
initialScene: SceneKey,
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 1ae999282afa..7988e0e4e416 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
@@ -203,26 +203,28 @@ class ElementTest {
val elementSize = 50.dp
val elementOffset = 20.dp
- lateinit var changeScene: (SceneKey) -> Unit
-
- rule.testTransition(
- from = SceneA,
- to = SceneB,
- transitionLayout = { currentScene, onChangeScene ->
- changeScene = onChangeScene
-
- SceneTransitionLayout(
- currentScene,
- onChangeScene,
+ val state =
+ rule.runOnUiThread {
+ MutableSceneTransitionLayoutState(
+ SceneA,
transitions {
from(SceneA, to = SceneB) { spec = tween }
from(SceneB, to = SceneC) { spec = tween }
},
- // Disable interruptions so that the current transition is directly removed when
- // starting a new one.
+ // Disable interruptions so that the current transition is directly removed
+ // when starting a new one.
enableInterruptions = false,
- ) {
+ )
+ }
+
+ lateinit var coroutineScope: CoroutineScope
+ rule.testTransition(
+ state = state,
+ to = SceneB,
+ transitionLayout = { state ->
+ coroutineScope = rememberCoroutineScope()
+ SceneTransitionLayout(state) {
scene(SceneA) {
Box(Modifier.size(layoutSize)) {
// Transformed element
@@ -243,7 +245,7 @@ class ElementTest {
onElement(TestElements.Bar).assertExists()
// Start transition from SceneB to SceneC
- changeScene(SceneC)
+ rule.runOnUiThread { state.setTargetScene(SceneC, coroutineScope) }
}
at(3 * frameDuration) { onElement(TestElements.Bar).assertIsNotDisplayed() }
@@ -340,18 +342,16 @@ class ElementTest {
@Test
fun elementIsReusedBetweenScenes() {
- var currentScene by mutableStateOf(SceneA)
+ val state = rule.runOnUiThread { MutableSceneTransitionLayoutState(SceneA) }
var sceneCState by mutableStateOf(0)
val key = TestElements.Foo
var nullableLayoutImpl: SceneTransitionLayoutImpl? = null
+ lateinit var coroutineScope: CoroutineScope
rule.setContent {
+ coroutineScope = rememberCoroutineScope()
SceneTransitionLayoutForTesting(
- state =
- updateSceneTransitionLayoutState(
- currentScene = currentScene,
- onChangeScene = { currentScene = it }
- ),
+ state = state,
onLayoutImpl = { nullableLayoutImpl = it },
) {
scene(SceneA) { /* Nothing */ }
@@ -375,7 +375,7 @@ class ElementTest {
assertThat(layoutImpl.elements).isEmpty()
// Scene B: element is in the map.
- currentScene = SceneB
+ rule.runOnUiThread { state.setTargetScene(SceneB, coroutineScope) }
rule.waitForIdle()
assertThat(layoutImpl.elements.keys).containsExactly(key)
@@ -383,7 +383,7 @@ class ElementTest {
assertThat(element.sceneStates.keys).containsExactly(SceneB)
// Scene C, state 0: the same element is reused.
- currentScene = SceneC
+ rule.runOnUiThread { state.setTargetScene(SceneC, coroutineScope) }
sceneCState = 0
rule.waitForIdle()
@@ -472,12 +472,13 @@ class ElementTest {
@Test
fun elementModifierSupportsUpdates() {
+ val state = rule.runOnUiThread { MutableSceneTransitionLayoutState(SceneA) }
var key by mutableStateOf(TestElements.Foo)
var nullableLayoutImpl: SceneTransitionLayoutImpl? = null
rule.setContent {
SceneTransitionLayoutForTesting(
- state = updateSceneTransitionLayoutState(currentScene = SceneA, onChangeScene = {}),
+ state = state,
onLayoutImpl = { nullableLayoutImpl = it },
) {
scene(SceneA) { Box(Modifier.element(key)) }
@@ -521,11 +522,12 @@ class ElementTest {
rule.waitUntil(timeoutMillis = 10_000) { animationFinished }
}
+ val state = rule.runOnUiThread { MutableSceneTransitionLayoutState(SceneA) }
rule.setContent {
scrollScope = rememberCoroutineScope()
SceneTransitionLayoutForTesting(
- state = updateSceneTransitionLayoutState(currentScene = SceneA, onChangeScene = {}),
+ state = state,
onLayoutImpl = { nullableLayoutImpl = it },
) {
scene(SceneA) {
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ObservableTransitionStateTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ObservableTransitionStateTest.kt
index 55431354b693..f717301dba38 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ObservableTransitionStateTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ObservableTransitionStateTest.kt
@@ -40,7 +40,13 @@ class ObservableTransitionStateTest {
@Test
fun testObservableTransitionState() = runTest {
- lateinit var state: SceneTransitionLayoutState
+ val state =
+ rule.runOnUiThread {
+ MutableSceneTransitionLayoutState(
+ SceneA,
+ EmptyTestTransitions,
+ )
+ }
// Collect the current observable state into [observableState].
// TODO(b/290184746): Use collectValues {} once it is extracted into a library that can be
@@ -63,16 +69,9 @@ class ObservableTransitionStateTest {
}
rule.testTransition(
- from = SceneA,
+ state = state,
to = SceneB,
- transitionLayout = { currentScene, onChangeScene ->
- state =
- updateSceneTransitionLayoutState(
- currentScene,
- onChangeScene,
- EmptyTestTransitions
- )
-
+ transitionLayout = {
SceneTransitionLayout(state = state) {
scene(SceneA) {}
scene(SceneB) {}
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/PredictiveBackHandlerTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/PredictiveBackHandlerTest.kt
new file mode 100644
index 000000000000..6522eb33bd49
--- /dev/null
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/PredictiveBackHandlerTest.kt
@@ -0,0 +1,159 @@
+/*
+ * 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.activity.BackEventCompat
+import androidx.activity.ComponentActivity
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.test.junit4.createAndroidComposeRule
+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 org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class PredictiveBackHandlerTest {
+ // We use createAndroidComposeRule() here and not createComposeRule() because we need an
+ // activity for testBack().
+ @get:Rule val rule = createAndroidComposeRule<ComponentActivity>()
+
+ @Test
+ fun testBack() {
+ val layoutState = rule.runOnUiThread { MutableSceneTransitionLayoutState(SceneA) }
+ rule.setContent {
+ SceneTransitionLayout(layoutState) {
+ scene(SceneA, mapOf(Back to SceneB)) { Box(Modifier.fillMaxSize()) }
+ scene(SceneB) { Box(Modifier.fillMaxSize()) }
+ }
+ }
+
+ assertThat(layoutState.transitionState).hasCurrentScene(SceneA)
+
+ rule.runOnUiThread { rule.activity.onBackPressedDispatcher.onBackPressed() }
+ rule.waitForIdle()
+ assertThat(layoutState.transitionState).hasCurrentScene(SceneB)
+ }
+
+ @Test
+ fun testPredictiveBack() {
+ val layoutState = rule.runOnUiThread { MutableSceneTransitionLayoutState(SceneA) }
+ rule.setContent {
+ SceneTransitionLayout(layoutState) {
+ scene(SceneA, mapOf(Back to SceneB)) { Box(Modifier.fillMaxSize()) }
+ scene(SceneB) { Box(Modifier.fillMaxSize()) }
+ }
+ }
+
+ assertThat(layoutState.transitionState).hasCurrentScene(SceneA)
+
+ // Start back.
+ val dispatcher = rule.activity.onBackPressedDispatcher
+ rule.runOnUiThread {
+ dispatcher.dispatchOnBackStarted(backEvent())
+ dispatcher.dispatchOnBackProgressed(backEvent(progress = 0.4f))
+ }
+
+ val transition = assertThat(layoutState.transitionState).isTransition()
+ assertThat(transition).hasFromScene(SceneA)
+ assertThat(transition).hasToScene(SceneB)
+ assertThat(transition).hasProgress(0.4f)
+
+ // Cancel it.
+ rule.runOnUiThread { dispatcher.dispatchOnBackCancelled() }
+ rule.waitForIdle()
+ assertThat(layoutState.transitionState).hasCurrentScene(SceneA)
+ assertThat(layoutState.transitionState).isIdle()
+
+ // Start again and commit it.
+ rule.runOnUiThread {
+ dispatcher.dispatchOnBackStarted(backEvent())
+ dispatcher.dispatchOnBackProgressed(backEvent(progress = 0.4f))
+ dispatcher.onBackPressed()
+ }
+ rule.waitForIdle()
+ assertThat(layoutState.transitionState).hasCurrentScene(SceneB)
+ assertThat(layoutState.transitionState).isIdle()
+ }
+
+ @Test
+ fun interruptedPredictiveBackDoesNotCallCanChangeScene() {
+ var canChangeSceneCalled = false
+ val layoutState =
+ rule.runOnUiThread {
+ MutableSceneTransitionLayoutState(
+ SceneA,
+ canChangeScene = {
+ canChangeSceneCalled = true
+ true
+ },
+ )
+ }
+
+ lateinit var coroutineScope: CoroutineScope
+ rule.setContent {
+ coroutineScope = rememberCoroutineScope()
+ SceneTransitionLayout(layoutState) {
+ scene(SceneA, mapOf(Back to SceneB)) { Box(Modifier.fillMaxSize()) }
+ scene(SceneB) { Box(Modifier.fillMaxSize()) }
+ scene(SceneC) { Box(Modifier.fillMaxSize()) }
+ }
+ }
+
+ assertThat(layoutState.transitionState).hasCurrentScene(SceneA)
+
+ // Start back.
+ val dispatcher = rule.activity.onBackPressedDispatcher
+ rule.runOnUiThread { dispatcher.dispatchOnBackStarted(backEvent()) }
+
+ val predictiveTransition = assertThat(layoutState.transitionState).isTransition()
+ assertThat(predictiveTransition).hasFromScene(SceneA)
+ assertThat(predictiveTransition).hasToScene(SceneB)
+
+ // Start a new transition to C.
+ rule.runOnUiThread { layoutState.setTargetScene(SceneC, coroutineScope) }
+ val newTransition = assertThat(layoutState.transitionState).isTransition()
+ assertThat(newTransition).hasFromScene(SceneA)
+ assertThat(newTransition).hasToScene(SceneC)
+
+ // Commit the back gesture. It shouldn't call canChangeScene given that the back transition
+ // was interrupted.
+ rule.runOnUiThread { dispatcher.onBackPressed() }
+ rule.waitForIdle()
+ assertThat(layoutState.transitionState).hasCurrentScene(SceneC)
+ assertThat(layoutState.transitionState).isIdle()
+ assertThat(predictiveTransition).hasCurrentScene(SceneA)
+ assertThat(canChangeSceneCalled).isFalse()
+ }
+
+ private fun backEvent(progress: Float = 0f): BackEventCompat {
+ return BackEventCompat(
+ touchX = 0f,
+ touchY = 0f,
+ progress = progress,
+ swipeEdge = BackEventCompat.EDGE_LEFT,
+ )
+ }
+}
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 1c8efb82fd24..1ec10793363e 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
@@ -16,8 +16,6 @@
package com.android.compose.animation.scene
-import androidx.activity.BackEventCompat
-import androidx.activity.ComponentActivity
import androidx.compose.animation.core.FastOutSlowInEasing
import androidx.compose.animation.core.LinearEasing
import androidx.compose.animation.core.tween
@@ -31,6 +29,8 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@@ -41,7 +41,7 @@ import androidx.compose.ui.test.assertHeightIsEqualTo
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.assertPositionInRootIsEqualTo
import androidx.compose.ui.test.assertWidthIsEqualTo
-import androidx.compose.ui.test.junit4.createAndroidComposeRule
+import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onChild
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.onNodeWithText
@@ -58,6 +58,7 @@ import com.android.compose.test.assertSizeIsEqualTo
import com.android.compose.test.subjects.DpOffsetSubject
import com.android.compose.test.subjects.assertThat
import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.CoroutineScope
import org.junit.Assert.assertThrows
import org.junit.Rule
import org.junit.Test
@@ -69,23 +70,27 @@ class SceneTransitionLayoutTest {
private val LayoutSize = 300.dp
}
- private var currentScene by mutableStateOf(SceneA)
- private lateinit var layoutState: SceneTransitionLayoutState
+ private lateinit var coroutineScope: CoroutineScope
+ private lateinit var layoutState: MutableSceneTransitionLayoutState
+ private var currentScene: SceneKey
+ get() = layoutState.transitionState.currentScene
+ set(value) {
+ rule.runOnUiThread { layoutState.setTargetScene(value, coroutineScope) }
+ }
- // We use createAndroidComposeRule() here and not createComposeRule() because we need an
- // activity for testBack().
- @get:Rule val rule = createAndroidComposeRule<ComponentActivity>()
+ @get:Rule val rule = createComposeRule()
/** The content under test. */
@Composable
private fun TestContent(enableInterruptions: Boolean = true) {
- layoutState =
- updateSceneTransitionLayoutState(
- currentScene,
- { currentScene = it },
+ coroutineScope = rememberCoroutineScope()
+ layoutState = remember {
+ MutableSceneTransitionLayoutState(
+ SceneA,
EmptyTestTransitions,
enableInterruptions = enableInterruptions,
)
+ }
SceneTransitionLayout(
state = layoutState,
@@ -164,52 +169,6 @@ class SceneTransitionLayoutTest {
}
@Test
- fun testBack() {
- rule.setContent { TestContent() }
-
- assertThat(layoutState.transitionState).hasCurrentScene(SceneA)
-
- rule.runOnUiThread { rule.activity.onBackPressedDispatcher.onBackPressed() }
- rule.waitForIdle()
- assertThat(layoutState.transitionState).hasCurrentScene(SceneB)
- }
-
- @Test
- fun testPredictiveBack() {
- rule.setContent { TestContent() }
-
- assertThat(layoutState.transitionState).hasCurrentScene(SceneA)
-
- // Start back.
- val dispatcher = rule.activity.onBackPressedDispatcher
- rule.runOnUiThread {
- dispatcher.dispatchOnBackStarted(backEvent())
- dispatcher.dispatchOnBackProgressed(backEvent(progress = 0.4f))
- }
-
- val transition = assertThat(layoutState.transitionState).isTransition()
- assertThat(transition).hasFromScene(SceneA)
- assertThat(transition).hasToScene(SceneB)
- assertThat(transition).hasProgress(0.4f)
-
- // Cancel it.
- rule.runOnUiThread { dispatcher.dispatchOnBackCancelled() }
- rule.waitForIdle()
- assertThat(layoutState.transitionState).hasCurrentScene(SceneA)
- assertThat(layoutState.transitionState).isIdle()
-
- // Start again and commit it.
- rule.runOnUiThread {
- dispatcher.dispatchOnBackStarted(backEvent())
- dispatcher.dispatchOnBackProgressed(backEvent(progress = 0.4f))
- dispatcher.onBackPressed()
- }
- rule.waitForIdle()
- assertThat(layoutState.transitionState).hasCurrentScene(SceneB)
- assertThat(layoutState.transitionState).isIdle()
- }
-
- @Test
fun testTransitionState() {
rule.setContent { TestContent() }
assertThat(layoutState.transitionState).isIdle()
@@ -218,23 +177,15 @@ class SceneTransitionLayoutTest {
// We will advance the clock manually.
rule.mainClock.autoAdvance = false
- // Change the current scene. Until composition is triggered, this won't change the layout
- // state.
+ // Change the current scene.
currentScene = SceneB
- 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()
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.
+ // starting time. We are still at progress = 0f.
rule.mainClock.advanceTimeByFrame()
assertThat(transition).hasProgress(0f)
@@ -275,12 +226,9 @@ class SceneTransitionLayoutTest {
// Pause animations to test the state mid-transition.
rule.mainClock.autoAdvance = false
- // Go to scene B and let the animation start. See [testLayoutState()] and
- // [androidx.compose.ui.test.MainTestClock] to understand why we need to advance the clock
- // by 2 frames to be at the start of the animation.
+ // Go to scene B and let the animation start.
currentScene = SceneB
rule.mainClock.advanceTimeByFrame()
- rule.mainClock.advanceTimeByFrame()
// Advance to the middle of the animation.
rule.mainClock.advanceTimeBy(TestTransitionDuration / 2)
@@ -311,7 +259,6 @@ class SceneTransitionLayoutTest {
// Animate to scene C, let the animation start then go to the middle of the transition.
currentScene = SceneC
rule.mainClock.advanceTimeByFrame()
- rule.mainClock.advanceTimeByFrame()
rule.mainClock.advanceTimeBy(TestTransitionDuration / 2)
// In Scene C, foo is at the bottom start of the layout and has a size of 150.dp. The
@@ -409,24 +356,24 @@ class SceneTransitionLayoutTest {
fun multipleTransitionsWillComposeMultipleScenes() {
val duration = 10 * 16L
- var currentScene: SceneKey by mutableStateOf(SceneA)
- lateinit var state: SceneTransitionLayoutState
- rule.setContent {
- state =
- updateSceneTransitionLayoutState(
- currentScene = currentScene,
- onChangeScene = { currentScene = it },
- transitions =
- transitions {
- from(SceneA, to = SceneB) {
- spec = tween(duration.toInt(), easing = LinearEasing)
- }
- from(SceneB, to = SceneC) {
- spec = tween(duration.toInt(), easing = LinearEasing)
- }
+ val state =
+ rule.runOnUiThread {
+ MutableSceneTransitionLayoutState(
+ SceneA,
+ transitions {
+ from(SceneA, to = SceneB) {
+ spec = tween(duration.toInt(), easing = LinearEasing)
}
+ from(SceneB, to = SceneC) {
+ spec = tween(duration.toInt(), easing = LinearEasing)
+ }
+ }
)
+ }
+ lateinit var coroutineScope: CoroutineScope
+ rule.setContent {
+ coroutineScope = rememberCoroutineScope()
SceneTransitionLayout(state) {
scene(SceneA) { Box(Modifier.testTag("aRoot").fillMaxSize()) }
scene(SceneB) { Box(Modifier.testTag("bRoot").fillMaxSize()) }
@@ -444,12 +391,11 @@ class SceneTransitionLayoutTest {
rule.mainClock.autoAdvance = false
// Start A => B and go to the middle of the transition.
- currentScene = SceneB
+ rule.runOnUiThread { state.setTargetScene(SceneB, coroutineScope) }
- // We need to tick 2 frames after changing [currentScene] before the animation actually
+ // We need to tick 1 frames after changing [currentScene] before the animation actually
// starts.
rule.mainClock.advanceTimeByFrame()
- rule.mainClock.advanceTimeByFrame()
rule.mainClock.advanceTimeBy(duration / 2)
rule.waitForIdle()
@@ -462,8 +408,7 @@ class SceneTransitionLayoutTest {
rule.onNodeWithTag("cRoot").assertDoesNotExist()
// Start B => C.
- currentScene = SceneC
- rule.mainClock.advanceTimeByFrame()
+ rule.runOnUiThread { state.setTargetScene(SceneC, coroutineScope) }
rule.mainClock.advanceTimeByFrame()
rule.waitForIdle()
@@ -517,12 +462,7 @@ class SceneTransitionLayoutTest {
assertThrows(IllegalStateException::class.java) {
rule.setContent {
SceneTransitionLayout(
- state =
- updateSceneTransitionLayoutState(
- currentScene = currentScene,
- onChangeScene = { currentScene = it },
- transitions = EmptyTestTransitions
- ),
+ state = remember { MutableSceneTransitionLayoutState(SceneA) },
modifier = Modifier.size(LayoutSize),
) {
// from SceneA to SceneA
@@ -560,13 +500,4 @@ class SceneTransitionLayoutTest {
assertThat(keyInB).isEqualTo(SceneB)
assertThat(keyInC).isEqualTo(SceneC)
}
-
- private fun backEvent(progress: Float = 0f): BackEventCompat {
- return BackEventCompat(
- touchX = 0f,
- touchY = 0f,
- progress = progress,
- swipeEdge = BackEventCompat.EDGE_LEFT,
- )
- }
}
diff --git a/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/TestSceneScope.kt b/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/TestSceneScope.kt
index de46f7209c84..fbd557f3cbb3 100644
--- a/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/TestSceneScope.kt
+++ b/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/TestSceneScope.kt
@@ -27,12 +27,6 @@ fun TestSceneScope(
content: @Composable SceneScope.() -> Unit,
) {
val currentScene = remember { SceneKey("current") }
- SceneTransitionLayout(
- currentScene,
- onChangeScene = { /* do nothing */},
- transitions = remember { transitions {} },
- modifier,
- ) {
- scene(currentScene, content = content)
- }
+ val state = remember { MutableSceneTransitionLayoutState(currentScene) }
+ SceneTransitionLayout(state, modifier) { scene(currentScene, content = content) }
}
diff --git a/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/TestTransition.kt b/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/TestTransition.kt
index 6724851dbec5..a37d78ef8a71 100644
--- a/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/TestTransition.kt
+++ b/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/TestTransition.kt
@@ -19,13 +19,14 @@ package com.android.compose.animation.scene
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.semantics.SemanticsNode
import androidx.compose.ui.test.SemanticsNodeInteraction
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
import androidx.compose.ui.test.junit4.ComposeContentTestRule
+import kotlinx.coroutines.CoroutineScope
import platform.test.motion.MotionTestRule
import platform.test.motion.RecordedMotion
import platform.test.motion.compose.ComposeRecordingSpec
@@ -95,20 +96,24 @@ fun ComposeContentTestRule.testTransition(
builder: TransitionTestBuilder.() -> Unit,
) {
testTransition(
- from = fromScene,
+ state =
+ runOnUiThread {
+ MutableSceneTransitionLayoutState(
+ fromScene,
+ transitions { from(fromScene, to = toScene, builder = transition) }
+ )
+ },
to = toScene,
- transitionLayout = { currentScene, onChangeScene ->
+ transitionLayout = { state ->
SceneTransitionLayout(
- currentScene,
- onChangeScene,
- transitions { from(fromScene, to = toScene, builder = transition) },
+ state,
layoutModifier,
) {
scene(fromScene, content = fromSceneContent)
scene(toScene, content = toSceneContent)
}
},
- builder,
+ builder = builder,
)
}
@@ -172,21 +177,19 @@ fun MotionTestRule<ComposeToolkit>.recordTransition(
)
}
-/**
- * Test the transition between two scenes of [transitionLayout][SceneTransitionLayout] at different
- * points in time.
- */
+/** Test the transition from [state] to [to]. */
fun ComposeContentTestRule.testTransition(
- from: SceneKey,
+ state: MutableSceneTransitionLayoutState,
to: SceneKey,
- transitionLayout:
- @Composable
- (
- currentScene: SceneKey,
- onChangeScene: (SceneKey) -> Unit,
- ) -> Unit,
+ transitionLayout: @Composable (state: MutableSceneTransitionLayoutState) -> Unit,
builder: TransitionTestBuilder.() -> Unit,
) {
+ val currentScene = state.transitionState.currentScene
+ check(currentScene != to) {
+ "The 'to' scene (${to.debugName}) should be different from the state current scene " +
+ "(${currentScene.debugName})"
+ }
+
val test = transitionTest(builder)
val assertionScope =
object : TransitionTestAssertionScope {
@@ -198,8 +201,11 @@ fun ComposeContentTestRule.testTransition(
}
}
- var currentScene by mutableStateOf(from)
- setContent { transitionLayout(currentScene, { currentScene = it }) }
+ lateinit var coroutineScope: CoroutineScope
+ setContent {
+ coroutineScope = rememberCoroutineScope()
+ transitionLayout(state)
+ }
// Wait for the UI to be idle then test the before state.
waitForIdle()
@@ -209,14 +215,8 @@ fun ComposeContentTestRule.testTransition(
mainClock.autoAdvance = false
// Change the current scene.
- currentScene = to
-
- // Advance by a frame to trigger recomposition, which will start the transition (i.e. it will
- // change the transitionState to be a Transition) in a LaunchedEffect.
- mainClock.advanceTimeByFrame()
-
- // Advance by another frame so that the animator we started gets its initial value and clock
- // starting time. We are now at progress = 0f.
+ runOnUiThread { state.setTargetScene(to, coroutineScope) }
+ waitForIdle()
mainClock.advanceTimeByFrame()
waitForIdle()
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt
index 20f87a059656..9e0af97e76e4 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt
@@ -65,7 +65,7 @@ class DefaultClockProvider(
throw IllegalArgumentException("$id is unsupported by $TAG")
}
- // TODO: Update placeholder to actual resource
+ // TODO(b/352049256): Update placeholder to actual resource
return resources.getDrawable(R.drawable.clock_default_thumbnail, null)
}
}
diff --git a/packages/SystemUI/lint-baseline.xml b/packages/SystemUI/lint-baseline.xml
index 525839de0a60..b4c839f08607 100644
--- a/packages/SystemUI/lint-baseline.xml
+++ b/packages/SystemUI/lint-baseline.xml
@@ -9168,39 +9168,6 @@
<issue
id="UnclosedTrace"
- message="The `beginSection()` call is not always closed with a matching `endSection()` because the code in between may return early"
- errorLine1=" Trace.beginSection(&quot;KeyguardViewMediator#handleKeyguardDone&quot;);"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java"
- line="2654"
- column="15"/>
- </issue>
-
- <issue
- id="UnclosedTrace"
- message="The `beginSection()` call is not always closed with a matching `endSection()` because the code in between may return early"
- errorLine1=" Trace.beginSection(&quot;KeyguardViewMediator#handleShow&quot;);"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java"
- line="2780"
- column="15"/>
- </issue>
-
- <issue
- id="UnclosedTrace"
- message="The `beginSection()` call is not always closed with a matching `endSection()` because the code in between may return early"
- errorLine1=" Trace.beginSection(&quot;KeyguardViewMediator#handleStartKeyguardExitAnimation&quot;);"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java"
- line="3011"
- column="15"/>
- </issue>
-
- <issue
- id="UnclosedTrace"
message="The `traceBegin()` call is not always closed with a matching `traceEnd()` because the code in between may return early"
errorLine1=" Trace.traceBegin(Trace.TRACE_TAG_APP, &quot;MediaControlPanel#bindPlayer&lt;&quot; + key + &quot;>&quot;);"
errorLine2=" ~~~~~~~~~~">
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalBackupRestoreStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalBackupRestoreStartableTest.kt
index 722eb2b9b622..60aea92ab3bd 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalBackupRestoreStartableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalBackupRestoreStartableTest.kt
@@ -20,6 +20,9 @@ import android.appwidget.AppWidgetManager
import android.content.Context
import android.content.Intent
import android.content.mockedContext
+import android.os.Handler
+import android.os.fakeExecutorHandler
+import android.provider.Settings.Secure.USER_SETUP_COMPLETE
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -27,11 +30,13 @@ import com.android.systemui.broadcast.FakeBroadcastDispatcher
import com.android.systemui.broadcast.broadcastDispatcher
import com.android.systemui.communal.domain.interactor.CommunalInteractor
import com.android.systemui.communal.widgets.CommunalWidgetModule
+import com.android.systemui.concurrency.fakeExecutor
import com.android.systemui.kosmos.testScope
import com.android.systemui.log.logcatLogBuffer
import com.android.systemui.testKosmos
-import com.android.systemui.util.mockito.any
-import com.android.systemui.util.mockito.kotlinArgumentCaptor
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.settings.SecureSettings
+import com.android.systemui.util.settings.fakeSettings
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -41,6 +46,8 @@ import org.mockito.Mock
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.any
+import org.mockito.kotlin.argumentCaptor
@SmallTest
@RunWith(AndroidJUnit4::class)
@@ -50,10 +57,13 @@ class CommunalBackupRestoreStartableTest : SysuiTestCase() {
@Mock private lateinit var communalInteractor: CommunalInteractor
- private val mapCaptor = kotlinArgumentCaptor<Map<Int, Int>>()
+ private val mapCaptor = argumentCaptor<Map<Int, Int>>()
private lateinit var context: Context
private lateinit var broadcastDispatcher: FakeBroadcastDispatcher
+ private lateinit var secureSettings: SecureSettings
+ private lateinit var handler: Handler
+ private lateinit var fakeExecutor: FakeExecutor
private lateinit var underTest: CommunalBackupRestoreStartable
@Before
@@ -62,18 +72,28 @@ class CommunalBackupRestoreStartableTest : SysuiTestCase() {
context = kosmos.mockedContext
broadcastDispatcher = kosmos.broadcastDispatcher
+ secureSettings = kosmos.fakeSettings
+ handler = kosmos.fakeExecutorHandler
+ fakeExecutor = kosmos.fakeExecutor
+
+ secureSettings.putInt(USER_SETUP_COMPLETE, 0)
underTest =
CommunalBackupRestoreStartable(
broadcastDispatcher,
communalInteractor,
logcatLogBuffer("CommunalBackupRestoreStartable"),
+ secureSettings,
+ handler,
)
}
@Test
- fun testRestoreWidgetsUponHostRestored() =
+ fun restoreWidgets_userSetUpComplete_performRestore() =
testScope.runTest {
+ // User set up complete
+ secureSettings.putInt(USER_SETUP_COMPLETE, 1)
+
underTest.start()
// Verify restore widgets not called
@@ -94,7 +114,7 @@ class CommunalBackupRestoreStartableTest : SysuiTestCase() {
// Verify restore widgets called
verify(communalInteractor).restoreWidgets(mapCaptor.capture())
- val oldToNewWidgetIdMap = mapCaptor.value
+ val oldToNewWidgetIdMap = mapCaptor.firstValue
assertThat(oldToNewWidgetIdMap)
.containsExactlyEntriesIn(
mapOf(
@@ -106,10 +126,54 @@ class CommunalBackupRestoreStartableTest : SysuiTestCase() {
}
@Test
- fun testDoNotRestoreWidgetsIfNotForCommunalWidgetHost() =
+ fun restoreWidgets_userSetUpNotComplete_restoreWhenUserSetupComplete() =
testScope.runTest {
underTest.start()
+ // Verify restore widgets not called
+ verify(communalInteractor, never()).restoreWidgets(any())
+
+ // Trigger app widget host restored
+ val intent =
+ Intent().apply {
+ action = AppWidgetManager.ACTION_APPWIDGET_HOST_RESTORED
+ putExtra(
+ AppWidgetManager.EXTRA_HOST_ID,
+ CommunalWidgetModule.APP_WIDGET_HOST_ID
+ )
+ putExtra(AppWidgetManager.EXTRA_APPWIDGET_OLD_IDS, intArrayOf(1, 2, 3))
+ putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, intArrayOf(7, 8, 9))
+ }
+ broadcastDispatcher.sendIntentToMatchingReceiversOnly(context, intent)
+
+ // Verify restore widgets not called because user setup not complete
+ verify(communalInteractor, never()).restoreWidgets(any())
+
+ // User setup complete
+ secureSettings.putInt(USER_SETUP_COMPLETE, 1)
+ fakeExecutor.runAllReady()
+
+ // Verify restore widgets called
+ verify(communalInteractor).restoreWidgets(mapCaptor.capture())
+ val oldToNewWidgetIdMap = mapCaptor.firstValue
+ assertThat(oldToNewWidgetIdMap)
+ .containsExactlyEntriesIn(
+ mapOf(
+ Pair(1, 7),
+ Pair(2, 8),
+ Pair(3, 9),
+ )
+ )
+ }
+
+ @Test
+ fun restoreWidgets_broadcastNotForCommunalWidgetHost_doNotPerformRestore() =
+ testScope.runTest {
+ // User set up complete
+ secureSettings.putInt(USER_SETUP_COMPLETE, 1)
+
+ underTest.start()
+
// Trigger app widget host restored, but for another host
val hostId = CommunalWidgetModule.APP_WIDGET_HOST_ID + 1
val intent =
@@ -126,8 +190,11 @@ class CommunalBackupRestoreStartableTest : SysuiTestCase() {
}
@Test
- fun testAbortRestoreWidgetsIfOldToNewIdsMappingInvalid() =
+ fun restoreWidgets_oldToNewIdsMappingInvalid_abortRestore() =
testScope.runTest {
+ // User set up complete
+ secureSettings.putInt(USER_SETUP_COMPLETE, 1)
+
underTest.start()
// Trigger app widget host restored, but new ids list is one too many for old ids
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalOngoingContentStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalOngoingContentStartableTest.kt
new file mode 100644
index 000000000000..2f949335d42a
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalOngoingContentStartableTest.kt
@@ -0,0 +1,89 @@
+/*
+ * 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.communal
+
+import android.platform.test.annotations.EnableFlags
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.Flags.FLAG_COMMUNAL_HUB
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.communal.data.repository.fakeCommunalMediaRepository
+import com.android.systemui.communal.data.repository.fakeCommunalSmartspaceRepository
+import com.android.systemui.communal.domain.interactor.communalInteractor
+import com.android.systemui.communal.domain.interactor.setCommunalEnabled
+import com.android.systemui.flags.Flags
+import com.android.systemui.flags.fakeFeatureFlagsClassic
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@EnableFlags(FLAG_COMMUNAL_HUB)
+@RunWith(AndroidJUnit4::class)
+class CommunalOngoingContentStartableTest : SysuiTestCase() {
+ private val kosmos = testKosmos()
+ private val testScope = kosmos.testScope
+
+ private val mediaRepository = kosmos.fakeCommunalMediaRepository
+ private val smartspaceRepository = kosmos.fakeCommunalSmartspaceRepository
+ private val featureFlags =
+ kosmos.fakeFeatureFlagsClassic.apply { set(Flags.COMMUNAL_SERVICE_ENABLED, true) }
+
+ private lateinit var underTest: CommunalOngoingContentStartable
+
+ @Before
+ fun setUp() {
+ underTest =
+ CommunalOngoingContentStartable(
+ bgScope = kosmos.applicationCoroutineScope,
+ communalInteractor = kosmos.communalInteractor,
+ communalMediaRepository = mediaRepository,
+ communalSmartspaceRepository = smartspaceRepository,
+ featureFlags = featureFlags,
+ )
+ }
+
+ @Test
+ fun testListenForOngoingContentWhenCommunalIsEnabled() =
+ testScope.runTest {
+ underTest.start()
+ runCurrent()
+
+ assertThat(mediaRepository.isListening()).isFalse()
+ assertThat(smartspaceRepository.isListening()).isFalse()
+
+ kosmos.setCommunalEnabled(true)
+ runCurrent()
+
+ assertThat(mediaRepository.isListening()).isTrue()
+ assertThat(smartspaceRepository.isListening()).isTrue()
+
+ kosmos.setCommunalEnabled(false)
+ runCurrent()
+
+ assertThat(mediaRepository.isListening()).isFalse()
+ assertThat(smartspaceRepository.isListening()).isFalse()
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt
index cf145471e55f..0de036988337 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt
@@ -27,6 +27,9 @@ import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.dock.dockManager
import com.android.systemui.dock.fakeDockManager
+import com.android.systemui.flags.Flags.COMMUNAL_SERVICE_ENABLED
+import com.android.systemui.flags.fakeFeatureFlagsClassic
+import com.android.systemui.flags.featureFlagsClassic
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
@@ -66,6 +69,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
fun setUp() {
with(kosmos) {
fakeSettings.putInt(Settings.System.SCREEN_OFF_TIMEOUT, SCREEN_TIMEOUT)
+ kosmos.fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, true)
underTest =
CommunalSceneStartable(
@@ -76,6 +80,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
keyguardInteractor = keyguardInteractor,
systemSettings = fakeSettings,
notificationShadeWindowController = notificationShadeWindowController,
+ featureFlagsClassic = kosmos.fakeFeatureFlagsClassic,
applicationScope = applicationCoroutineScope,
bgScope = applicationCoroutineScope,
mainDispatcher = testDispatcher,
@@ -451,6 +456,24 @@ class CommunalSceneStartableTest : SysuiTestCase() {
}
}
+ @Test
+ fun transitionFromDozingToGlanceableHub_forcesCommunal() =
+ with(kosmos) {
+ testScope.runTest {
+ val scene by collectLastValue(communalSceneInteractor.currentScene)
+ communalSceneInteractor.changeScene(CommunalScenes.Blank)
+ assertThat(scene).isEqualTo(CommunalScenes.Blank)
+
+ fakeKeyguardTransitionRepository.sendTransitionSteps(
+ from = KeyguardState.DOZING,
+ to = KeyguardState.GLANCEABLE_HUB,
+ testScope = this
+ )
+
+ assertThat(scene).isEqualTo(CommunalScenes.Communal)
+ }
+ }
+
private fun TestScope.updateDocked(docked: Boolean) =
with(kosmos) {
runCurrent()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/db/DefaultWidgetPopulationTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/db/DefaultWidgetPopulationTest.kt
new file mode 100644
index 000000000000..ad2c42fd1f09
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/db/DefaultWidgetPopulationTest.kt
@@ -0,0 +1,157 @@
+/*
+ * 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.communal.data.db
+
+import android.content.ComponentName
+import android.os.UserHandle
+import android.os.UserManager
+import androidx.sqlite.db.SupportSQLiteDatabase
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.communal.data.db.DefaultWidgetPopulation.SkipReason.RESTORED_FROM_BACKUP
+import com.android.systemui.communal.widgets.CommunalWidgetHost
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.log.logcatLogBuffer
+import com.android.systemui.testKosmos
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.kotlin.any
+import org.mockito.kotlin.anyOrNull
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.never
+import org.mockito.kotlin.verify
+
+@SmallTest
+@OptIn(ExperimentalCoroutinesApi::class)
+@RunWith(AndroidJUnit4::class)
+class DefaultWidgetPopulationTest : SysuiTestCase() {
+ private val kosmos = testKosmos()
+ private val testScope = kosmos.testScope
+
+ private val communalWidgetHost =
+ mock<CommunalWidgetHost> {
+ var nextId = 0
+ on { allocateIdAndBindWidget(any(), anyOrNull()) }.thenAnswer { nextId++ }
+ }
+ private val communalWidgetDao = mock<CommunalWidgetDao>()
+ private val database = mock<SupportSQLiteDatabase>()
+ private val mainUser = UserHandle(0)
+ private val userManager =
+ mock<UserManager> {
+ on { mainUser }.thenReturn(mainUser)
+ on { getUserSerialNumber(0) }.thenReturn(0)
+ }
+
+ private val defaultWidgets =
+ arrayOf(
+ "com.android.test_package_1/fake_widget_1",
+ "com.android.test_package_2/fake_widget_2",
+ "com.android.test_package_3/fake_widget_3",
+ )
+
+ private lateinit var underTest: DefaultWidgetPopulation
+
+ @Before
+ fun setUp() {
+ underTest =
+ DefaultWidgetPopulation(
+ bgScope = kosmos.applicationCoroutineScope,
+ communalWidgetHost = communalWidgetHost,
+ communalWidgetDaoProvider = { communalWidgetDao },
+ defaultWidgets = defaultWidgets,
+ logBuffer = logcatLogBuffer("DefaultWidgetPopulationTest"),
+ userManager = userManager,
+ )
+ }
+
+ @Test
+ fun testPopulateDefaultWidgetsWhenDatabaseCreated() =
+ testScope.runTest {
+ // Database created
+ underTest.onCreate(database)
+ runCurrent()
+
+ // Verify default widgets bound
+ verify(communalWidgetHost)
+ .allocateIdAndBindWidget(
+ provider = eq(ComponentName.unflattenFromString(defaultWidgets[0])!!),
+ user = eq(mainUser),
+ )
+ verify(communalWidgetHost)
+ .allocateIdAndBindWidget(
+ provider = eq(ComponentName.unflattenFromString(defaultWidgets[1])!!),
+ user = eq(mainUser),
+ )
+ verify(communalWidgetHost)
+ .allocateIdAndBindWidget(
+ provider = eq(ComponentName.unflattenFromString(defaultWidgets[2])!!),
+ user = eq(mainUser),
+ )
+
+ // Verify default widgets added in database
+ verify(communalWidgetDao)
+ .addWidget(
+ widgetId = 0,
+ componentName = defaultWidgets[0],
+ priority = 3,
+ userSerialNumber = 0,
+ )
+ verify(communalWidgetDao)
+ .addWidget(
+ widgetId = 1,
+ componentName = defaultWidgets[1],
+ priority = 2,
+ userSerialNumber = 0,
+ )
+ verify(communalWidgetDao)
+ .addWidget(
+ widgetId = 2,
+ componentName = defaultWidgets[2],
+ priority = 1,
+ userSerialNumber = 0,
+ )
+ }
+
+ @Test
+ fun testSkipDefaultWidgetsPopulation() =
+ testScope.runTest {
+ // Skip default widgets population
+ underTest.skipDefaultWidgetsPopulation(RESTORED_FROM_BACKUP)
+
+ // Database created
+ underTest.onCreate(database)
+ runCurrent()
+
+ // Verify no widget bounded or added to the database
+ verify(communalWidgetHost, never()).allocateIdAndBindWidget(any(), any())
+ verify(communalWidgetDao, never())
+ .addWidget(
+ widgetId = anyInt(),
+ componentName = any(),
+ priority = anyInt(),
+ userSerialNumber = anyInt(),
+ )
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalMediaRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalMediaRepositoryImplTest.kt
index 407bf4cac633..dd280223f203 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalMediaRepositoryImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalMediaRepositoryImplTest.kt
@@ -20,46 +20,41 @@ 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.kosmos.testScope
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.media.controls.domain.pipeline.MediaDataManager
import com.android.systemui.media.controls.shared.model.MediaData
-import com.android.systemui.util.mockito.KotlinArgumentCaptor
+import com.android.systemui.testKosmos
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
import org.junit.runner.RunWith
-import org.mockito.Mock
import org.mockito.Mockito.verify
-import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.argumentCaptor
+import org.mockito.kotlin.mock
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(AndroidJUnit4::class)
@android.platform.test.annotations.EnabledOnRavenwood
class CommunalMediaRepositoryImplTest : SysuiTestCase() {
- @Mock private lateinit var mediaDataManager: MediaDataManager
- @Mock private lateinit var mediaData: MediaData
- @Mock private lateinit var tableLogBuffer: TableLogBuffer
+ private val mediaDataManager = mock<MediaDataManager>()
+ private val mediaData = mock<MediaData>()
+ private val tableLogBuffer = mock<TableLogBuffer>()
private lateinit var underTest: CommunalMediaRepositoryImpl
- private val mediaDataListenerCaptor: KotlinArgumentCaptor<MediaDataManager.Listener> by lazy {
- KotlinArgumentCaptor(MediaDataManager.Listener::class.java)
- }
+ private val mediaDataListenerCaptor = argumentCaptor<MediaDataManager.Listener>()
- private val testDispatcher = StandardTestDispatcher()
- private val testScope = TestScope(testDispatcher)
+ private val kosmos = testKosmos()
+ private val testScope = kosmos.testScope
@Before
fun setUp() {
- MockitoAnnotations.initMocks(this)
-
underTest =
CommunalMediaRepositoryImpl(
mediaDataManager,
@@ -78,6 +73,8 @@ class CommunalMediaRepositoryImplTest : SysuiTestCase() {
@Test
fun mediaModel_updatesWhenMediaDataLoaded() =
testScope.runTest {
+ underTest.startListening()
+
// Listener is added
verify(mediaDataManager).addListener(mediaDataListenerCaptor.capture())
@@ -89,7 +86,7 @@ class CommunalMediaRepositoryImplTest : SysuiTestCase() {
// Change to media available and notify the listener.
whenever(mediaDataManager.hasActiveMediaOrRecommendation()).thenReturn(true)
whenever(mediaData.createdTimestampMillis).thenReturn(1234L)
- mediaDataListenerCaptor.value.onMediaDataLoaded("key", null, mediaData)
+ mediaDataListenerCaptor.firstValue.onMediaDataLoaded("key", null, mediaData)
runCurrent()
// Media active now returns true.
@@ -100,12 +97,14 @@ class CommunalMediaRepositoryImplTest : SysuiTestCase() {
@Test
fun mediaModel_updatesWhenMediaDataRemoved() =
testScope.runTest {
+ underTest.startListening()
+
// Listener is added
verify(mediaDataManager).addListener(mediaDataListenerCaptor.capture())
// Change to media available and notify the listener.
whenever(mediaDataManager.hasActiveMediaOrRecommendation()).thenReturn(true)
- mediaDataListenerCaptor.value.onMediaDataLoaded("key", null, mediaData)
+ mediaDataListenerCaptor.firstValue.onMediaDataLoaded("key", null, mediaData)
runCurrent()
// Media active now returns true.
@@ -114,7 +113,7 @@ class CommunalMediaRepositoryImplTest : SysuiTestCase() {
// Change to media unavailable and notify the listener.
whenever(mediaDataManager.hasActiveMediaOrRecommendation()).thenReturn(false)
- mediaDataListenerCaptor.value.onMediaDataRemoved("key", false)
+ mediaDataListenerCaptor.firstValue.onMediaDataRemoved("key", false)
runCurrent()
// Media active now returns false.
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalSmartspaceRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalSmartspaceRepositoryImplTest.kt
new file mode 100644
index 000000000000..c1816ed3e5bf
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalSmartspaceRepositoryImplTest.kt
@@ -0,0 +1,319 @@
+/*
+ * 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.communal.data.repository
+
+import android.app.smartspace.SmartspaceTarget
+import android.app.smartspace.flags.Flags.FLAG_REMOTE_VIEWS
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.communal.smartspace.CommunalSmartspaceController
+import com.android.systemui.concurrency.fakeExecutor
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.plugins.BcSmartspaceDataPlugin.SmartspaceTargetListener
+import com.android.systemui.testKosmos
+import com.android.systemui.util.time.fakeSystemClock
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.any
+import org.mockito.kotlin.argumentCaptor
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.never
+import org.mockito.kotlin.verify
+
+@SmallTest
+@OptIn(ExperimentalCoroutinesApi::class)
+@RunWith(AndroidJUnit4::class)
+class CommunalSmartspaceRepositoryImplTest : SysuiTestCase() {
+ private val kosmos = testKosmos()
+ private val testScope = kosmos.testScope
+
+ private val listenerCaptor = argumentCaptor<SmartspaceTargetListener>()
+
+ private val smartspaceController = mock<CommunalSmartspaceController>()
+ private val fakeExecutor = kosmos.fakeExecutor
+ private val systemClock = kosmos.fakeSystemClock
+
+ private lateinit var underTest: CommunalSmartspaceRepositoryImpl
+
+ @Before
+ fun setUp() {
+ underTest =
+ CommunalSmartspaceRepositoryImpl(
+ smartspaceController,
+ fakeExecutor,
+ systemClock,
+ )
+ }
+
+ @DisableFlags(FLAG_REMOTE_VIEWS)
+ @Test
+ fun startListening_remoteViewsFlagDisabled_doNotListenForSmartspaceUpdates() =
+ testScope.runTest {
+ underTest.startListening()
+ fakeExecutor.runAllReady()
+
+ verify(smartspaceController, never()).addListener(any())
+ }
+
+ @EnableFlags(FLAG_REMOTE_VIEWS)
+ @Test
+ fun startListening_remoteViewsFlagEnabled_listenForSmartspaceUpdates() =
+ testScope.runTest {
+ underTest.startListening()
+ fakeExecutor.runAllReady()
+
+ // Verify listener added
+ val listener = captureSmartspaceTargetListener()
+
+ underTest.stopListening()
+ fakeExecutor.runAllReady()
+
+ // Verify listener removed
+ verify(smartspaceController).removeListener(listener)
+ }
+
+ @EnableFlags(FLAG_REMOTE_VIEWS)
+ @Test
+ fun communalTimers_onlyShowTimersWithRemoteViews() =
+ testScope.runTest {
+ underTest.startListening()
+
+ val communalTimers by collectLastValue(underTest.timers)
+ runCurrent()
+ fakeExecutor.runAllReady()
+
+ with(captureSmartspaceTargetListener()) {
+ onSmartspaceTargetsUpdated(
+ listOf(
+ // Invalid. Not a timer
+ mock<SmartspaceTarget> {
+ on { smartspaceTargetId }.doReturn("weather")
+ on { featureType }.doReturn(SmartspaceTarget.FEATURE_WEATHER)
+ },
+ // Invalid. RemoteViews absent
+ mock<SmartspaceTarget> {
+ on { smartspaceTargetId }.doReturn("timer-0-started")
+ on { featureType }.doReturn(SmartspaceTarget.FEATURE_TIMER)
+ on { remoteViews }.doReturn(null)
+ on { creationTimeMillis }.doReturn(1000)
+ },
+ // Valid
+ mock<SmartspaceTarget> {
+ on { smartspaceTargetId }.doReturn("timer-1-started")
+ on { featureType }.doReturn(SmartspaceTarget.FEATURE_TIMER)
+ on { remoteViews }.doReturn(mock())
+ on { creationTimeMillis }.doReturn(2000)
+ },
+ )
+ )
+ }
+ runCurrent()
+
+ // Verify that only the valid target is listed
+ assertThat(communalTimers).hasSize(1)
+ assertThat(communalTimers?.first()?.smartspaceTargetId).isEqualTo("timer-1-started")
+ }
+
+ @EnableFlags(FLAG_REMOTE_VIEWS)
+ @Test
+ fun communalTimers_cacheCreationTime() =
+ testScope.runTest {
+ underTest.startListening()
+
+ val communalTimers by collectLastValue(underTest.timers)
+ runCurrent()
+ fakeExecutor.runAllReady()
+
+ val listener = captureSmartspaceTargetListener()
+ listener.onSmartspaceTargetsUpdated(
+ listOf(
+ mock<SmartspaceTarget> {
+ on { smartspaceTargetId }.doReturn("timer-0-started")
+ on { featureType }.doReturn(SmartspaceTarget.FEATURE_TIMER)
+ on { remoteViews }.doReturn(mock())
+ on { creationTimeMillis }.doReturn(1000)
+ },
+ )
+ )
+ runCurrent()
+
+ // Verify that the creation time is the current time, not the creation time passed in
+ // the target, because this value can be inaccurate (due to b/318535930).
+ val currentTime = systemClock.currentTimeMillis()
+ assertThat(communalTimers?.get(0)?.createdTimestampMillis).isEqualTo(currentTime)
+ assertThat(communalTimers?.get(0)?.createdTimestampMillis).isNotEqualTo(1000)
+
+ // A second timer is added.
+ listener.onSmartspaceTargetsUpdated(
+ listOf(
+ mock<SmartspaceTarget> {
+ on { smartspaceTargetId }.doReturn("timer-0-started")
+ on { featureType }.doReturn(SmartspaceTarget.FEATURE_TIMER)
+ on { remoteViews }.doReturn(mock())
+ on { creationTimeMillis }.doReturn(2000)
+ },
+ mock<SmartspaceTarget> {
+ on { smartspaceTargetId }.doReturn("timer-1-started")
+ on { featureType }.doReturn(SmartspaceTarget.FEATURE_TIMER)
+ on { remoteViews }.doReturn(mock())
+ on { creationTimeMillis }.doReturn(3000)
+ },
+ )
+ )
+ runCurrent()
+
+ // Verify that the created timestamp for the first time is consistent
+ assertThat(communalTimers?.get(0)?.createdTimestampMillis).isEqualTo(currentTime)
+
+ // Verify that the second timer has a new creation time
+ assertThat(communalTimers?.get(1)?.createdTimestampMillis)
+ .isEqualTo(systemClock.currentTimeMillis())
+ }
+
+ @EnableFlags(FLAG_REMOTE_VIEWS)
+ @Test
+ fun communalTimers_creationTimeRemovedFromCacheWhenTimerRemoved() =
+ testScope.runTest {
+ underTest.startListening()
+
+ val communalTimers by collectLastValue(underTest.timers)
+ runCurrent()
+ fakeExecutor.runAllReady()
+
+ // Start timer 0
+ val listener = captureSmartspaceTargetListener()
+ listener.onSmartspaceTargetsUpdated(
+ listOf(
+ mock<SmartspaceTarget> {
+ on { smartspaceTargetId }.doReturn("timer-0-started")
+ on { featureType }.doReturn(SmartspaceTarget.FEATURE_TIMER)
+ on { remoteViews }.doReturn(mock())
+ on { creationTimeMillis }.doReturn(1000)
+ },
+ )
+ )
+ runCurrent()
+
+ // Verify timer 0 creation time
+ val expectedCreationTimeForTimer0 = systemClock.currentTimeMillis()
+ assertThat(communalTimers?.first()?.createdTimestampMillis)
+ .isEqualTo(expectedCreationTimeForTimer0)
+
+ // Advance some time
+ systemClock.advanceTime(1000)
+
+ // Start timer 1
+ listener.onSmartspaceTargetsUpdated(
+ listOf(
+ mock<SmartspaceTarget> {
+ on { smartspaceTargetId }.doReturn("timer-0-started")
+ on { featureType }.doReturn(SmartspaceTarget.FEATURE_TIMER)
+ on { remoteViews }.doReturn(mock())
+ on { creationTimeMillis }.doReturn(1000)
+ },
+ mock<SmartspaceTarget> {
+ on { smartspaceTargetId }.doReturn("timer-1-started")
+ on { featureType }.doReturn(SmartspaceTarget.FEATURE_TIMER)
+ on { remoteViews }.doReturn(mock())
+ on { creationTimeMillis }.doReturn(2000)
+ },
+ )
+ )
+ runCurrent()
+
+ // Verify timer 1 creation time is new
+ val expectedCreationTimeForTimer1 = expectedCreationTimeForTimer0 + 1000
+ assertThat(communalTimers?.get(1)?.createdTimestampMillis)
+ .isEqualTo(expectedCreationTimeForTimer1)
+
+ // Removed timer 0
+ listener.onSmartspaceTargetsUpdated(
+ listOf(
+ mock<SmartspaceTarget> {
+ on { smartspaceTargetId }.doReturn("timer-1-started")
+ on { featureType }.doReturn(SmartspaceTarget.FEATURE_TIMER)
+ on { remoteViews }.doReturn(mock())
+ on { creationTimeMillis }.doReturn(2000)
+ },
+ )
+ )
+ runCurrent()
+
+ // Verify timer 0 removed, and timer 1 creation time is correct
+ assertThat(communalTimers).hasSize(1)
+ assertThat(communalTimers?.first()?.createdTimestampMillis)
+ .isEqualTo(expectedCreationTimeForTimer1)
+
+ // Advance some time
+ systemClock.advanceTime(1000)
+
+ // Start timer 0 again. Technically this is a new timer, but timers can reused stable
+ // ids.
+ listener.onSmartspaceTargetsUpdated(
+ listOf(
+ mock<SmartspaceTarget> {
+ on { smartspaceTargetId }.doReturn("timer-1-started")
+ on { featureType }.doReturn(SmartspaceTarget.FEATURE_TIMER)
+ on { remoteViews }.doReturn(mock())
+ on { creationTimeMillis }.doReturn(2000)
+ },
+ mock<SmartspaceTarget> {
+ on { smartspaceTargetId }.doReturn("timer-0-started")
+ on { featureType }.doReturn(SmartspaceTarget.FEATURE_TIMER)
+ on { remoteViews }.doReturn(mock())
+ on { creationTimeMillis }.doReturn(3000)
+ },
+ )
+ )
+ runCurrent()
+
+ // Verify new timer added, and timer 1 creation time is still correct
+ assertThat(communalTimers).hasSize(2)
+ assertThat(communalTimers?.get(0)?.createdTimestampMillis)
+ .isEqualTo(expectedCreationTimeForTimer1)
+
+ // Verify creation time for the new timer is new, meaning that cache for timer 0 was
+ // removed when it was removed
+ assertThat(communalTimers?.get(1)?.createdTimestampMillis)
+ .isEqualTo(expectedCreationTimeForTimer1 + 1000)
+ }
+
+ @Test
+ fun stableId() {
+ assertThat(CommunalSmartspaceRepositoryImpl.stableId("timer-0-12345-started"))
+ .isEqualTo("timer-0")
+ assertThat(CommunalSmartspaceRepositoryImpl.stableId("timer-1-67890-paused"))
+ .isEqualTo("timer-1")
+ assertThat(CommunalSmartspaceRepositoryImpl.stableId("i_am_an_unexpected_id"))
+ .isEqualTo("i_am_an_unexpected_id")
+ }
+
+ private fun captureSmartspaceTargetListener(): SmartspaceTargetListener {
+ verify(smartspaceController).addListener(listenerCaptor.capture())
+ return listenerCaptor.firstValue
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryImplTest.kt
index 6ce6cdb32a12..c707ebf0a2c4 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryImplTest.kt
@@ -24,6 +24,7 @@ import android.content.ComponentName
import android.content.applicationContext
import android.graphics.Bitmap
import android.os.UserHandle
+import android.os.userManager
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -33,6 +34,7 @@ import com.android.systemui.communal.data.backup.CommunalBackupUtils
import com.android.systemui.communal.data.db.CommunalItemRank
import com.android.systemui.communal.data.db.CommunalWidgetDao
import com.android.systemui.communal.data.db.CommunalWidgetItem
+import com.android.systemui.communal.data.db.defaultWidgetPopulation
import com.android.systemui.communal.nano.CommunalHubState
import com.android.systemui.communal.proto.toByteArray
import com.android.systemui.communal.shared.model.CommunalWidgetContentModel
@@ -47,10 +49,6 @@ import com.android.systemui.log.LogBuffer
import com.android.systemui.log.logcatLogBuffer
import com.android.systemui.res.R
import com.android.systemui.testKosmos
-import com.android.systemui.util.mockito.any
-import com.android.systemui.util.mockito.mock
-import com.android.systemui.util.mockito.whenever
-import com.android.systemui.util.mockito.withArgCaptor
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
@@ -59,11 +57,16 @@ import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mock
import org.mockito.Mockito.eq
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.any
+import org.mockito.kotlin.argumentCaptor
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.whenever
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@@ -77,6 +80,9 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
@Mock private lateinit var communalWidgetDao: CommunalWidgetDao
@Mock private lateinit var backupManager: BackupManager
+ private val communalHubStateCaptor = argumentCaptor<CommunalHubState>()
+ private val componentNameCaptor = argumentCaptor<ComponentName>()
+
private lateinit var backupUtils: CommunalBackupUtils
private lateinit var logBuffer: LogBuffer
private lateinit var fakeWidgets: MutableStateFlow<Map<CommunalItemRank, CommunalWidgetItem>>
@@ -85,6 +91,10 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
private val kosmos = testKosmos()
private val testScope = kosmos.testScope
private val packageChangeRepository = kosmos.fakePackageChangeRepository
+ private val userManager = kosmos.userManager
+
+ private val mainUser = UserHandle(0)
+ private val workProfile = UserHandle(10)
private val fakeAllowlist =
listOf(
@@ -109,6 +119,9 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
whenever(communalWidgetDao.getWidgets()).thenReturn(fakeWidgets)
whenever(communalWidgetHost.appWidgetProviders).thenReturn(fakeProviders)
+ whenever(userManager.mainUser).thenReturn(mainUser)
+
+ restoreUser(mainUser)
underTest =
CommunalWidgetRepositoryImpl(
@@ -121,6 +134,8 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
backupManager,
backupUtils,
packageChangeRepository,
+ userManager,
+ kosmos.defaultWidgetPopulation,
)
}
@@ -128,7 +143,7 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
fun communalWidgets_queryWidgetsFromDb() =
testScope.runTest {
val communalItemRankEntry = CommunalItemRank(uid = 1L, rank = 1)
- val communalWidgetItemEntry = CommunalWidgetItem(uid = 1L, 1, "pk_name/cls_name", 1L)
+ val communalWidgetItemEntry = CommunalWidgetItem(uid = 1L, 1, "pk_name/cls_name", 1L, 0)
fakeWidgets.value = mapOf(communalItemRankEntry to communalWidgetItemEntry)
fakeProviders.value = mapOf(1 to providerInfoA)
@@ -154,13 +169,13 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
fakeWidgets.value =
mapOf(
CommunalItemRank(uid = 1L, rank = 1) to
- CommunalWidgetItem(uid = 1L, 1, "pk_1/cls_1", 1L),
+ CommunalWidgetItem(uid = 1L, 1, "pk_1/cls_1", 1L, 0),
CommunalItemRank(uid = 2L, rank = 2) to
- CommunalWidgetItem(uid = 2L, 2, "pk_2/cls_2", 2L),
+ CommunalWidgetItem(uid = 2L, 2, "pk_2/cls_2", 2L, 0),
CommunalItemRank(uid = 3L, rank = 3) to
- CommunalWidgetItem(uid = 3L, 3, "pk_3/cls_3", 3L),
+ CommunalWidgetItem(uid = 3L, 3, "pk_3/cls_3", 3L, 0),
CommunalItemRank(uid = 4L, rank = 4) to
- CommunalWidgetItem(uid = 4L, 4, "pk_4/cls_4", 4L),
+ CommunalWidgetItem(uid = 4L, 4, "pk_4/cls_4", 4L, 0),
)
fakeProviders.value =
mapOf(
@@ -192,9 +207,9 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
fakeWidgets.value =
mapOf(
CommunalItemRank(uid = 1L, rank = 1) to
- CommunalWidgetItem(uid = 1L, 1, "pk_1/cls_1", 1L),
+ CommunalWidgetItem(uid = 1L, 1, "pk_1/cls_1", 1L, 0),
CommunalItemRank(uid = 2L, rank = 2) to
- CommunalWidgetItem(uid = 2L, 2, "pk_2/cls_2", 2L),
+ CommunalWidgetItem(uid = 2L, 2, "pk_2/cls_2", 2L, 0),
)
fakeProviders.value =
mapOf(
@@ -249,7 +264,6 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
val provider = ComponentName("pkg_name", "cls_name")
val id = 1
val priority = 1
- val user = UserHandle(0)
whenever(communalWidgetHost.getAppWidgetInfo(id))
.thenReturn(PROVIDER_INFO_REQUIRES_CONFIGURATION)
whenever(
@@ -259,11 +273,12 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
)
)
.thenReturn(id)
- underTest.addWidget(provider, user, priority, kosmos.widgetConfiguratorSuccess)
+ underTest.addWidget(provider, mainUser, priority, kosmos.widgetConfiguratorSuccess)
runCurrent()
- verify(communalWidgetHost).allocateIdAndBindWidget(provider, user)
- verify(communalWidgetDao).addWidget(id, provider, priority)
+ verify(communalWidgetHost).allocateIdAndBindWidget(provider, mainUser)
+ verify(communalWidgetDao)
+ .addWidget(id, provider, priority, testUserSerialNumber(mainUser))
// Verify backup requested
verify(backupManager).dataChanged()
@@ -275,7 +290,6 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
val provider = ComponentName("pkg_name", "cls_name")
val id = 1
val priority = 1
- val user = UserHandle(0)
whenever(communalWidgetHost.getAppWidgetInfo(id))
.thenReturn(PROVIDER_INFO_REQUIRES_CONFIGURATION)
whenever(
@@ -285,11 +299,12 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
)
)
.thenReturn(id)
- underTest.addWidget(provider, user, priority, kosmos.widgetConfiguratorFail)
+ underTest.addWidget(provider, mainUser, priority, kosmos.widgetConfiguratorFail)
runCurrent()
- verify(communalWidgetHost).allocateIdAndBindWidget(provider, user)
- verify(communalWidgetDao, never()).addWidget(id, provider, priority)
+ verify(communalWidgetHost).allocateIdAndBindWidget(provider, mainUser)
+ verify(communalWidgetDao, never())
+ .addWidget(anyInt(), any<ComponentName>(), anyInt(), anyInt())
verify(appWidgetHost).deleteAppWidgetId(id)
// Verify backup not requested
@@ -302,7 +317,6 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
val provider = ComponentName("pkg_name", "cls_name")
val id = 1
val priority = 1
- val user = UserHandle(0)
whenever(communalWidgetHost.getAppWidgetInfo(id))
.thenReturn(PROVIDER_INFO_REQUIRES_CONFIGURATION)
whenever(
@@ -312,13 +326,14 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
)
)
.thenReturn(id)
- underTest.addWidget(provider, user, priority) {
+ underTest.addWidget(provider, mainUser, priority) {
throw IllegalStateException("some error")
}
runCurrent()
- verify(communalWidgetHost).allocateIdAndBindWidget(provider, user)
- verify(communalWidgetDao, never()).addWidget(id, provider, priority)
+ verify(communalWidgetHost).allocateIdAndBindWidget(provider, mainUser)
+ verify(communalWidgetDao, never())
+ .addWidget(anyInt(), any<ComponentName>(), anyInt(), anyInt())
verify(appWidgetHost).deleteAppWidgetId(id)
// Verify backup not requested
@@ -331,7 +346,6 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
val provider = ComponentName("pkg_name", "cls_name")
val id = 1
val priority = 1
- val user = UserHandle(0)
whenever(communalWidgetHost.getAppWidgetInfo(id))
.thenReturn(PROVIDER_INFO_CONFIGURATION_OPTIONAL)
whenever(
@@ -341,11 +355,12 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
)
)
.thenReturn(id)
- underTest.addWidget(provider, user, priority, kosmos.widgetConfiguratorFail)
+ underTest.addWidget(provider, mainUser, priority, kosmos.widgetConfiguratorFail)
runCurrent()
- verify(communalWidgetHost).allocateIdAndBindWidget(provider, user)
- verify(communalWidgetDao).addWidget(id, provider, priority)
+ verify(communalWidgetHost).allocateIdAndBindWidget(provider, mainUser)
+ verify(communalWidgetDao)
+ .addWidget(id, provider, priority, testUserSerialNumber(mainUser))
// Verify backup requested
verify(backupManager).dataChanged()
@@ -444,11 +459,8 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
runCurrent()
// Verify state restored, and widget 2 skipped
- val restoredState =
- withArgCaptor<CommunalHubState> {
- verify(communalWidgetDao).restoreCommunalHubState(capture())
- }
- val restoredWidgets = restoredState.widgets.toList()
+ verify(communalWidgetDao).restoreCommunalHubState(communalHubStateCaptor.capture())
+ val restoredWidgets = communalHubStateCaptor.firstValue.widgets.toList()
assertThat(restoredWidgets).hasSize(1)
val restoredWidget = restoredWidgets.first()
@@ -474,11 +486,8 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
runCurrent()
// Verify widget 1 and 2 are restored, and are now 11 and 12.
- val restoredState =
- withArgCaptor<CommunalHubState> {
- verify(communalWidgetDao).restoreCommunalHubState(capture())
- }
- val restoredWidgets = restoredState.widgets.toList()
+ verify(communalWidgetDao).restoreCommunalHubState(communalHubStateCaptor.capture())
+ val restoredWidgets = communalHubStateCaptor.firstValue.widgets.toList()
assertThat(restoredWidgets).hasSize(2)
val restoredWidget1 = restoredWidgets[0]
@@ -512,11 +521,8 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
runCurrent()
// Verify widget 1 and 2 are restored, and are now 1 and 12.
- val restoredState =
- withArgCaptor<CommunalHubState> {
- verify(communalWidgetDao).restoreCommunalHubState(capture())
- }
- val restoredWidgets = restoredState.widgets.toList()
+ verify(communalWidgetDao).restoreCommunalHubState(communalHubStateCaptor.capture())
+ val restoredWidgets = communalHubStateCaptor.firstValue.widgets.toList()
assertThat(restoredWidgets).hasSize(2)
val restoredWidget1 = restoredWidgets[0]
@@ -533,14 +539,134 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
}
@Test
+ fun restoreWidgets_undefinedUser_restoredAsMain() =
+ testScope.runTest {
+ // Write two widgets to file, both of which have user serial number undefined.
+ val fakeState =
+ CommunalHubState().apply {
+ widgets =
+ listOf(
+ CommunalHubState.CommunalWidgetItem().apply {
+ widgetId = 1
+ componentName = "pk_name/fake_widget_1"
+ rank = 1
+ userSerialNumber =
+ CommunalWidgetItem.USER_SERIAL_NUMBER_UNDEFINED
+ },
+ CommunalHubState.CommunalWidgetItem().apply {
+ widgetId = 2
+ componentName = "pk_name/fake_widget_2"
+ rank = 2
+ userSerialNumber =
+ CommunalWidgetItem.USER_SERIAL_NUMBER_UNDEFINED
+ },
+ )
+ .toTypedArray()
+ }
+ backupUtils.writeBytesToDisk(fakeState.toByteArray())
+
+ // Set up app widget host with widget ids.
+ setAppWidgetIds(listOf(11, 12))
+
+ // Restore widgets.
+ underTest.restoreWidgets(mapOf(Pair(1, 11), Pair(2, 12)))
+ runCurrent()
+
+ // Verify widget 1 and 2 are restored with the main user.
+ verify(communalWidgetDao).restoreCommunalHubState(communalHubStateCaptor.capture())
+ val restoredWidgets = communalHubStateCaptor.firstValue.widgets.toList()
+ assertThat(restoredWidgets).hasSize(2)
+
+ val restoredWidget1 = restoredWidgets[0]
+ assertThat(restoredWidget1.widgetId).isEqualTo(11)
+ assertThat(restoredWidget1.userSerialNumber).isEqualTo(testUserSerialNumber(mainUser))
+
+ val restoredWidget2 = restoredWidgets[1]
+ assertThat(restoredWidget2.widgetId).isEqualTo(12)
+ assertThat(restoredWidget2.userSerialNumber).isEqualTo(testUserSerialNumber(mainUser))
+ }
+
+ @Test
+ fun restoreWidgets_workProfileNotRestored_widgetSkipped() =
+ testScope.runTest {
+ // Write fake state to file
+ backupUtils.writeBytesToDisk(fakeStateWithWorkProfile.toByteArray())
+
+ // Set up app widget host with widget ids.
+ // (b/349852237) It's possible that the platform restores widgets even though their user
+ // is not restored.
+ setAppWidgetIds(listOf(11, 12))
+
+ // Restore widgets.
+ underTest.restoreWidgets(mapOf(Pair(1, 11), Pair(2, 12)))
+ runCurrent()
+
+ // Verify only widget 1 is restored. Widget 2 is skipped because it belongs to a work
+ // profile, which is not restored.
+ verify(communalWidgetDao).restoreCommunalHubState(communalHubStateCaptor.capture())
+ val restoredWidgets = communalHubStateCaptor.firstValue.widgets.toList()
+ assertThat(restoredWidgets).hasSize(1)
+
+ val restoredWidget = restoredWidgets[0]
+ assertThat(restoredWidget.widgetId).isEqualTo(11)
+ assertThat(restoredWidget.userSerialNumber).isEqualTo(testUserSerialNumber(mainUser))
+ }
+
+ @Test
+ fun restoreWidgets_workProfileRestored_manuallyBindWidget() =
+ testScope.runTest {
+ // Write fake state to file
+ backupUtils.writeBytesToDisk(fakeStateWithWorkProfile.toByteArray())
+
+ // Set up app widget host with widget ids.
+ // (b/349852237) It's possible that the platform restores widgets even though their user
+ // is not restored.
+ setAppWidgetIds(listOf(11, 12))
+
+ // Restore work profile.
+ restoreUser(workProfile)
+
+ val newWidgetId = 13
+ whenever(communalWidgetHost.allocateIdAndBindWidget(any(), any()))
+ .thenReturn(newWidgetId)
+
+ // Restore widgets.
+ underTest.restoreWidgets(mapOf(Pair(1, 11), Pair(2, 12)))
+ runCurrent()
+
+ // Verify widget 1 is restored.
+ verify(communalWidgetDao).restoreCommunalHubState(communalHubStateCaptor.capture())
+ val restoredWidgets = communalHubStateCaptor.firstValue.widgets.toList()
+ assertThat(restoredWidgets).hasSize(1)
+
+ val restoredWidget = restoredWidgets[0]
+ assertThat(restoredWidget.widgetId).isEqualTo(11)
+ assertThat(restoredWidget.userSerialNumber).isEqualTo(testUserSerialNumber(mainUser))
+
+ // Verify widget 2 (now 12) is removed from platform
+ verify(appWidgetHost).deleteAppWidgetId(12)
+
+ // Verify work profile widget is manually bound
+ verify(communalWidgetDao)
+ .addWidget(
+ eq(newWidgetId),
+ componentNameCaptor.capture(),
+ eq(2),
+ eq(testUserSerialNumber(workProfile))
+ )
+ assertThat(componentNameCaptor.firstValue)
+ .isEqualTo(ComponentName("pk_name", "fake_widget_2"))
+ }
+
+ @Test
fun pendingWidgets() =
testScope.runTest {
fakeWidgets.value =
mapOf(
CommunalItemRank(uid = 1L, rank = 1) to
- CommunalWidgetItem(uid = 1L, 1, "pk_1/cls_1", 1L),
+ CommunalWidgetItem(uid = 1L, 1, "pk_1/cls_1", 1L, 0),
CommunalItemRank(uid = 2L, rank = 2) to
- CommunalWidgetItem(uid = 2L, 2, "pk_2/cls_2", 2L),
+ CommunalWidgetItem(uid = 2L, 2, "pk_2/cls_2", 2L, 0),
)
// Widget 1 is installed
@@ -554,7 +680,7 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
sessionId = 1,
packageName = "pk_2",
icon = fakeIcon,
- user = UserHandle.CURRENT,
+ user = mainUser,
)
)
)
@@ -572,7 +698,7 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
priority = 2,
packageName = "pk_2",
icon = fakeIcon,
- user = UserHandle.CURRENT,
+ user = mainUser,
),
)
}
@@ -583,7 +709,7 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
fakeWidgets.value =
mapOf(
CommunalItemRank(uid = 1L, rank = 1) to
- CommunalWidgetItem(uid = 1L, 1, "pk_1/cls_1", 1L),
+ CommunalWidgetItem(uid = 1L, 1, "pk_1/cls_1", 1L, 0),
)
// Widget 1 is pending install
@@ -594,7 +720,7 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
sessionId = 1,
packageName = "pk_1",
icon = fakeIcon,
- user = UserHandle.CURRENT,
+ user = mainUser,
)
)
)
@@ -607,7 +733,7 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
priority = 1,
packageName = "pk_1",
icon = fakeIcon,
- user = UserHandle.CURRENT,
+ user = mainUser,
),
)
@@ -633,6 +759,20 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
whenever(appWidgetHost.appWidgetIds).thenReturn(ids.toIntArray())
}
+ // Commonly the user id and user serial number are the same, but for testing purposes use a
+ // simple algorithm to map a user id to a different user serial number to make sure the correct
+ // value is used.
+ private fun testUserSerialNumber(user: UserHandle): Int {
+ return user.identifier + 100
+ }
+
+ private fun restoreUser(user: UserHandle) {
+ whenever(backupManager.getUserForAncestralSerialNumber(user.identifier.toLong()))
+ .thenReturn(user)
+ whenever(userManager.getUserSerialNumber(user.identifier))
+ .thenReturn(testUserSerialNumber(user))
+ }
+
private companion object {
val PROVIDER_INFO_REQUIRES_CONFIGURATION =
AppWidgetProviderInfo().apply { configure = ComponentName("test.pkg", "test.cmp") }
@@ -650,11 +790,32 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
widgetId = 1
componentName = "pk_name/fake_widget_1"
rank = 1
+ userSerialNumber = 0
+ },
+ CommunalHubState.CommunalWidgetItem().apply {
+ widgetId = 2
+ componentName = "pk_name/fake_widget_2"
+ rank = 2
+ userSerialNumber = 0
+ },
+ )
+ .toTypedArray()
+ }
+ val fakeStateWithWorkProfile =
+ CommunalHubState().apply {
+ widgets =
+ listOf(
+ CommunalHubState.CommunalWidgetItem().apply {
+ widgetId = 1
+ componentName = "pk_name/fake_widget_1"
+ rank = 1
+ userSerialNumber = 0
},
CommunalHubState.CommunalWidgetItem().apply {
widgetId = 2
componentName = "pk_name/fake_widget_2"
rank = 2
+ userSerialNumber = 10
},
)
.toTypedArray()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
index 7b26db50814e..5cdbe9ce5856 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
@@ -19,7 +19,6 @@ package com.android.systemui.communal.domain.interactor
import android.app.admin.DevicePolicyManager
import android.app.admin.devicePolicyManager
-import android.app.smartspace.SmartspaceTarget
import android.appwidget.AppWidgetProviderInfo
import android.content.Intent
import android.content.pm.UserInfo
@@ -36,14 +35,17 @@ import com.android.compose.animation.scene.ObservableTransitionState
import com.android.systemui.Flags.FLAG_COMMUNAL_HUB
import com.android.systemui.SysuiTestCase
import com.android.systemui.broadcast.broadcastDispatcher
+import com.android.systemui.communal.data.model.CommunalSmartspaceTimer
import com.android.systemui.communal.data.repository.FakeCommunalMediaRepository
import com.android.systemui.communal.data.repository.FakeCommunalPrefsRepository
import com.android.systemui.communal.data.repository.FakeCommunalSceneRepository
+import com.android.systemui.communal.data.repository.FakeCommunalSmartspaceRepository
import com.android.systemui.communal.data.repository.FakeCommunalTutorialRepository
import com.android.systemui.communal.data.repository.FakeCommunalWidgetRepository
import com.android.systemui.communal.data.repository.fakeCommunalMediaRepository
import com.android.systemui.communal.data.repository.fakeCommunalPrefsRepository
import com.android.systemui.communal.data.repository.fakeCommunalSceneRepository
+import com.android.systemui.communal.data.repository.fakeCommunalSmartspaceRepository
import com.android.systemui.communal.data.repository.fakeCommunalTutorialRepository
import com.android.systemui.communal.data.repository.fakeCommunalWidgetRepository
import com.android.systemui.communal.domain.model.CommunalContentModel
@@ -69,8 +71,6 @@ import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.settings.FakeUserTracker
import com.android.systemui.settings.fakeUserTracker
-import com.android.systemui.smartspace.data.repository.FakeSmartspaceRepository
-import com.android.systemui.smartspace.data.repository.fakeSmartspaceRepository
import com.android.systemui.testKosmos
import com.android.systemui.user.data.repository.FakeUserRepository
import com.android.systemui.user.data.repository.fakeUserRepository
@@ -114,7 +114,7 @@ class CommunalInteractorTest : SysuiTestCase() {
private lateinit var communalRepository: FakeCommunalSceneRepository
private lateinit var mediaRepository: FakeCommunalMediaRepository
private lateinit var widgetRepository: FakeCommunalWidgetRepository
- private lateinit var smartspaceRepository: FakeSmartspaceRepository
+ private lateinit var smartspaceRepository: FakeCommunalSmartspaceRepository
private lateinit var userRepository: FakeUserRepository
private lateinit var keyguardRepository: FakeKeyguardRepository
private lateinit var communalPrefsRepository: FakeCommunalPrefsRepository
@@ -135,7 +135,7 @@ class CommunalInteractorTest : SysuiTestCase() {
communalRepository = kosmos.fakeCommunalSceneRepository
mediaRepository = kosmos.fakeCommunalMediaRepository
widgetRepository = kosmos.fakeCommunalWidgetRepository
- smartspaceRepository = kosmos.fakeSmartspaceRepository
+ smartspaceRepository = kosmos.fakeCommunalSmartspaceRepository
userRepository = kosmos.fakeUserRepository
keyguardRepository = kosmos.fakeKeyguardRepository
editWidgetsActivityStarter = kosmos.editWidgetsActivityStarter
@@ -265,44 +265,6 @@ class CommunalInteractorTest : SysuiTestCase() {
}
@Test
- fun smartspace_onlyShowTimersWithRemoteViews() =
- testScope.runTest {
- // Keyguard showing, and tutorial completed.
- keyguardRepository.setKeyguardShowing(true)
- keyguardRepository.setKeyguardOccluded(false)
- tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED)
-
- // Not a timer
- val target1 = mock(SmartspaceTarget::class.java)
- whenever(target1.smartspaceTargetId).thenReturn("target1")
- whenever(target1.featureType).thenReturn(SmartspaceTarget.FEATURE_WEATHER)
- whenever(target1.remoteViews).thenReturn(mock(RemoteViews::class.java))
- whenever(target1.creationTimeMillis).thenReturn(0L)
-
- // Does not have RemoteViews
- val target2 = mock(SmartspaceTarget::class.java)
- whenever(target2.smartspaceTargetId).thenReturn("target2")
- whenever(target2.featureType).thenReturn(SmartspaceTarget.FEATURE_TIMER)
- whenever(target2.remoteViews).thenReturn(null)
- whenever(target2.creationTimeMillis).thenReturn(0L)
-
- // Timer and has RemoteViews
- val target3 = mock(SmartspaceTarget::class.java)
- whenever(target3.smartspaceTargetId).thenReturn("target3")
- whenever(target3.featureType).thenReturn(SmartspaceTarget.FEATURE_TIMER)
- whenever(target3.remoteViews).thenReturn(mock(RemoteViews::class.java))
- whenever(target3.creationTimeMillis).thenReturn(0L)
-
- val targets = listOf(target1, target2, target3)
- smartspaceRepository.setCommunalSmartspaceTargets(targets)
-
- val smartspaceContent by collectLastValue(underTest.getOngoingContent(true))
- assertThat(smartspaceContent?.size).isEqualTo(1)
- assertThat(smartspaceContent?.get(0)?.key)
- .isEqualTo(CommunalContentModel.KEY.smartspace("target3"))
- }
-
- @Test
fun smartspaceDynamicSizing_oneCard_fullSize() =
testSmartspaceDynamicSizing(
totalTargets = 1,
@@ -387,12 +349,12 @@ class CommunalInteractorTest : SysuiTestCase() {
keyguardRepository.setKeyguardOccluded(false)
tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED)
- val targets = mutableListOf<SmartspaceTarget>()
+ val targets = mutableListOf<CommunalSmartspaceTimer>()
for (index in 0 until totalTargets) {
targets.add(smartspaceTimer(index.toString()))
}
- smartspaceRepository.setCommunalSmartspaceTargets(targets)
+ smartspaceRepository.setTimers(targets)
val smartspaceContent by collectLastValue(underTest.getOngoingContent(true))
assertThat(smartspaceContent?.size).isEqualTo(totalTargets)
@@ -441,18 +403,18 @@ class CommunalInteractorTest : SysuiTestCase() {
// Timer1 started
val timer1 = smartspaceTimer("timer1", timestamp = 1L)
- smartspaceRepository.setCommunalSmartspaceTargets(listOf(timer1))
+ smartspaceRepository.setTimers(listOf(timer1))
// Umo started
mediaRepository.mediaActive(timestamp = 2L)
// Timer2 started
val timer2 = smartspaceTimer("timer2", timestamp = 3L)
- smartspaceRepository.setCommunalSmartspaceTargets(listOf(timer1, timer2))
+ smartspaceRepository.setTimers(listOf(timer1, timer2))
// Timer3 started
val timer3 = smartspaceTimer("timer3", timestamp = 4L)
- smartspaceRepository.setCommunalSmartspaceTargets(listOf(timer1, timer2, timer3))
+ smartspaceRepository.setTimers(listOf(timer1, timer2, timer3))
val ongoingContent by collectLastValue(underTest.getOngoingContent(true))
assertThat(ongoingContent?.size).isEqualTo(4)
@@ -1089,13 +1051,12 @@ class CommunalInteractorTest : SysuiTestCase() {
assertThat(showCommunalFromOccluded).isTrue()
}
- private fun smartspaceTimer(id: String, timestamp: Long = 0L): SmartspaceTarget {
- val timer = mock(SmartspaceTarget::class.java)
- whenever(timer.smartspaceTargetId).thenReturn(id)
- whenever(timer.featureType).thenReturn(SmartspaceTarget.FEATURE_TIMER)
- whenever(timer.remoteViews).thenReturn(mock(RemoteViews::class.java))
- whenever(timer.creationTimeMillis).thenReturn(timestamp)
- return timer
+ private fun smartspaceTimer(id: String, timestamp: Long = 0L): CommunalSmartspaceTimer {
+ return CommunalSmartspaceTimer(
+ smartspaceTargetId = id,
+ createdTimestampMillis = timestamp,
+ remoteViews = mock(RemoteViews::class.java)
+ )
}
private fun setKeyguardFeaturesDisabled(user: UserInfo, disabledFlags: Int) {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractorTest.kt
new file mode 100644
index 000000000000..e4916b1a7e46
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractorTest.kt
@@ -0,0 +1,126 @@
+/*
+ * 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.communal.domain.interactor
+
+import android.app.admin.DevicePolicyManager
+import android.app.admin.devicePolicyManager
+import android.content.Intent
+import android.content.pm.UserInfo
+import android.os.UserManager
+import android.os.userManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.broadcast.broadcastDispatcher
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.settings.FakeUserTracker
+import com.android.systemui.settings.fakeUserTracker
+import com.android.systemui.testKosmos
+import com.android.systemui.user.data.repository.FakeUserRepository
+import com.android.systemui.user.data.repository.fakeUserRepository
+import kotlinx.coroutines.test.runTest
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertNotNull
+import org.junit.Assert.assertNull
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers
+import org.mockito.kotlin.anyOrNull
+import org.mockito.kotlin.whenever
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class CommunalSettingsInteractorTest : SysuiTestCase() {
+
+ private lateinit var userManager: UserManager
+ private lateinit var userRepository: FakeUserRepository
+ private lateinit var userTracker: FakeUserTracker
+
+ private val kosmos = testKosmos()
+ private val testScope = kosmos.testScope
+
+ private lateinit var underTest: CommunalSettingsInteractor
+
+ @Before
+ fun setUp() {
+ userManager = kosmos.userManager
+ userRepository = kosmos.fakeUserRepository
+ userTracker = kosmos.fakeUserTracker
+
+ val userInfos = listOf(MAIN_USER_INFO, USER_INFO_WORK)
+ userRepository.setUserInfos(userInfos)
+ userTracker.set(
+ userInfos = userInfos,
+ selectedUserIndex = 0,
+ )
+
+ underTest = kosmos.communalSettingsInteractor
+ }
+
+ @Test
+ fun filterUsers_dontFilteredUsersWhenAllAreAllowed() =
+ testScope.runTest {
+ // If no users have any keyguard features disabled...
+ val disallowedUser by
+ collectLastValue(underTest.workProfileUserDisallowedByDevicePolicy)
+ // ...then the disallowed user should be null
+ assertNull(disallowedUser)
+ }
+
+ @Test
+ fun filterUsers_filterWorkProfileUserWhenDisallowed() =
+ testScope.runTest {
+ // If the work profile user has keyguard widgets disabled...
+ setKeyguardFeaturesDisabled(
+ USER_INFO_WORK,
+ DevicePolicyManager.KEYGUARD_DISABLE_WIDGETS_ALL
+ )
+ // ...then the disallowed user match the work profile
+ val disallowedUser by
+ collectLastValue(underTest.workProfileUserDisallowedByDevicePolicy)
+ assertNotNull(disallowedUser)
+ assertEquals(USER_INFO_WORK.id, disallowedUser!!.id)
+ }
+
+ private fun setKeyguardFeaturesDisabled(user: UserInfo, disabledFlags: Int) {
+ whenever(
+ kosmos.devicePolicyManager.getKeyguardDisabledFeatures(
+ anyOrNull(),
+ ArgumentMatchers.eq(user.id)
+ )
+ )
+ .thenReturn(disabledFlags)
+ kosmos.broadcastDispatcher.sendIntentToMatchingReceiversOnly(
+ context,
+ Intent(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
+ )
+ }
+
+ private companion object {
+ val MAIN_USER_INFO = UserInfo(0, "primary", UserInfo.FLAG_MAIN)
+ val USER_INFO_WORK =
+ UserInfo(
+ 10,
+ "work",
+ /* iconPath= */ "",
+ /* flags= */ 0,
+ UserManager.USER_TYPE_PROFILE_MANAGED,
+ )
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt
index 0190ccba3caa..b138fb3b779a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt
@@ -16,7 +16,6 @@
package com.android.systemui.communal.view.viewmodel
-import android.app.smartspace.SmartspaceTarget
import android.appwidget.AppWidgetProviderInfo
import android.content.ActivityNotFoundException
import android.content.Intent
@@ -32,12 +31,16 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.logging.UiEventLogger
import com.android.systemui.SysuiTestCase
+import com.android.systemui.communal.data.model.CommunalSmartspaceTimer
import com.android.systemui.communal.data.repository.FakeCommunalMediaRepository
+import com.android.systemui.communal.data.repository.FakeCommunalSmartspaceRepository
import com.android.systemui.communal.data.repository.FakeCommunalTutorialRepository
import com.android.systemui.communal.data.repository.FakeCommunalWidgetRepository
import com.android.systemui.communal.data.repository.fakeCommunalMediaRepository
+import com.android.systemui.communal.data.repository.fakeCommunalSmartspaceRepository
import com.android.systemui.communal.data.repository.fakeCommunalTutorialRepository
import com.android.systemui.communal.data.repository.fakeCommunalWidgetRepository
+import com.android.systemui.communal.domain.interactor.CommunalInteractor
import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor
import com.android.systemui.communal.domain.interactor.communalInteractor
import com.android.systemui.communal.domain.interactor.communalPrefsInteractor
@@ -57,8 +60,6 @@ import com.android.systemui.kosmos.testScope
import com.android.systemui.log.logcatLogBuffer
import com.android.systemui.media.controls.ui.view.MediaHost
import com.android.systemui.settings.fakeUserTracker
-import com.android.systemui.smartspace.data.repository.FakeSmartspaceRepository
-import com.android.systemui.smartspace.data.repository.fakeSmartspaceRepository
import com.android.systemui.testKosmos
import com.android.systemui.user.data.repository.fakeUserRepository
import com.android.systemui.util.mockito.any
@@ -76,6 +77,8 @@ import org.mockito.Mockito
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.spy
@SmallTest
@RunWith(AndroidJUnit4::class)
@@ -91,9 +94,10 @@ class CommunalEditModeViewModelTest : SysuiTestCase() {
private lateinit var tutorialRepository: FakeCommunalTutorialRepository
private lateinit var widgetRepository: FakeCommunalWidgetRepository
- private lateinit var smartspaceRepository: FakeSmartspaceRepository
+ private lateinit var smartspaceRepository: FakeCommunalSmartspaceRepository
private lateinit var mediaRepository: FakeCommunalMediaRepository
private lateinit var communalSceneInteractor: CommunalSceneInteractor
+ private lateinit var communalInteractor: CommunalInteractor
private val testableResources = context.orCreateTestableResources
@@ -105,9 +109,10 @@ class CommunalEditModeViewModelTest : SysuiTestCase() {
tutorialRepository = kosmos.fakeCommunalTutorialRepository
widgetRepository = kosmos.fakeCommunalWidgetRepository
- smartspaceRepository = kosmos.fakeSmartspaceRepository
+ smartspaceRepository = kosmos.fakeCommunalSmartspaceRepository
mediaRepository = kosmos.fakeCommunalMediaRepository
communalSceneInteractor = kosmos.communalSceneInteractor
+ communalInteractor = spy(kosmos.communalInteractor)
kosmos.fakeUserRepository.setUserInfos(listOf(MAIN_USER_INFO))
kosmos.fakeUserTracker.set(
userInfos = listOf(MAIN_USER_INFO),
@@ -119,7 +124,7 @@ class CommunalEditModeViewModelTest : SysuiTestCase() {
underTest =
CommunalEditModeViewModel(
communalSceneInteractor,
- kosmos.communalInteractor,
+ communalInteractor,
kosmos.communalSettingsInteractor,
kosmos.keyguardTransitionInteractor,
mediaHost,
@@ -152,11 +157,15 @@ class CommunalEditModeViewModelTest : SysuiTestCase() {
widgetRepository.setCommunalWidgets(widgets)
// Smartspace available.
- val target = Mockito.mock(SmartspaceTarget::class.java)
- whenever(target.smartspaceTargetId).thenReturn("target")
- whenever(target.featureType).thenReturn(SmartspaceTarget.FEATURE_TIMER)
- whenever(target.remoteViews).thenReturn(Mockito.mock(RemoteViews::class.java))
- smartspaceRepository.setCommunalSmartspaceTargets(listOf(target))
+ smartspaceRepository.setTimers(
+ listOf(
+ CommunalSmartspaceTimer(
+ smartspaceTargetId = "target",
+ createdTimestampMillis = 0L,
+ remoteViews = Mockito.mock(RemoteViews::class.java),
+ )
+ )
+ )
// Media playing.
mediaRepository.mediaActive()
@@ -342,6 +351,16 @@ class CommunalEditModeViewModelTest : SysuiTestCase() {
assertThat(showDisclaimer).isFalse()
}
+ @Test
+ fun scrollPosition_persistedOnEditCleanup() {
+ val index = 2
+ val offset = 30
+ underTest.onScrollPositionUpdated(index, offset)
+ underTest.cleanupEditModeState()
+
+ verify(communalInteractor).setScrollPosition(eq(index), eq(offset))
+ }
+
private companion object {
val MAIN_USER_INFO = UserInfo(0, "primary", UserInfo.FLAG_MAIN)
const val WIDGET_PICKER_PACKAGE_NAME = "widget_picker_package_name"
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
index d33877462ec6..c480aa8e4a3d 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
@@ -16,7 +16,6 @@
package com.android.systemui.communal.view.viewmodel
-import android.app.smartspace.SmartspaceTarget
import android.appwidget.AppWidgetProviderInfo
import android.content.pm.UserInfo
import android.os.UserHandle
@@ -27,14 +26,18 @@ import androidx.test.filters.SmallTest
import com.android.compose.animation.scene.ObservableTransitionState
import com.android.systemui.Flags.FLAG_COMMUNAL_HUB
import com.android.systemui.SysuiTestCase
+import com.android.systemui.communal.data.model.CommunalSmartspaceTimer
import com.android.systemui.communal.data.repository.FakeCommunalMediaRepository
import com.android.systemui.communal.data.repository.FakeCommunalSceneRepository
+import com.android.systemui.communal.data.repository.FakeCommunalSmartspaceRepository
import com.android.systemui.communal.data.repository.FakeCommunalTutorialRepository
import com.android.systemui.communal.data.repository.FakeCommunalWidgetRepository
import com.android.systemui.communal.data.repository.fakeCommunalMediaRepository
import com.android.systemui.communal.data.repository.fakeCommunalSceneRepository
+import com.android.systemui.communal.data.repository.fakeCommunalSmartspaceRepository
import com.android.systemui.communal.data.repository.fakeCommunalTutorialRepository
import com.android.systemui.communal.data.repository.fakeCommunalWidgetRepository
+import com.android.systemui.communal.domain.interactor.CommunalInteractor
import com.android.systemui.communal.domain.interactor.communalInteractor
import com.android.systemui.communal.domain.interactor.communalSceneInteractor
import com.android.systemui.communal.domain.interactor.communalSettingsInteractor
@@ -78,8 +81,6 @@ import com.android.systemui.settings.fakeUserTracker
import com.android.systemui.shade.ShadeTestUtil
import com.android.systemui.shade.domain.interactor.shadeInteractor
import com.android.systemui.shade.shadeTestUtil
-import com.android.systemui.smartspace.data.repository.FakeSmartspaceRepository
-import com.android.systemui.smartspace.data.repository.fakeSmartspaceRepository
import com.android.systemui.statusbar.KeyguardIndicationController
import com.android.systemui.testKosmos
import com.android.systemui.user.data.repository.FakeUserRepository
@@ -97,7 +98,9 @@ import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.eq
import org.mockito.kotlin.mock
+import org.mockito.kotlin.spy
import org.mockito.kotlin.whenever
import platform.test.runner.parameterized.ParameterizedAndroidJunit4
import platform.test.runner.parameterized.Parameters
@@ -115,12 +118,13 @@ class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() {
private lateinit var keyguardRepository: FakeKeyguardRepository
private lateinit var tutorialRepository: FakeCommunalTutorialRepository
private lateinit var widgetRepository: FakeCommunalWidgetRepository
- private lateinit var smartspaceRepository: FakeSmartspaceRepository
+ private lateinit var smartspaceRepository: FakeCommunalSmartspaceRepository
private lateinit var mediaRepository: FakeCommunalMediaRepository
private lateinit var userRepository: FakeUserRepository
private lateinit var shadeTestUtil: ShadeTestUtil
private lateinit var keyguardTransitionRepository: FakeKeyguardTransitionRepository
private lateinit var communalRepository: FakeCommunalSceneRepository
+ private lateinit var communalInteractor: CommunalInteractor
private lateinit var underTest: CommunalViewModel
@@ -136,7 +140,7 @@ class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() {
keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
tutorialRepository = kosmos.fakeCommunalTutorialRepository
widgetRepository = kosmos.fakeCommunalWidgetRepository
- smartspaceRepository = kosmos.fakeSmartspaceRepository
+ smartspaceRepository = kosmos.fakeCommunalSmartspaceRepository
mediaRepository = kosmos.fakeCommunalMediaRepository
userRepository = kosmos.fakeUserRepository
shadeTestUtil = kosmos.shadeTestUtil
@@ -154,6 +158,8 @@ class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() {
kosmos.powerInteractor.setAwakeForTest()
+ communalInteractor = spy(kosmos.communalInteractor)
+
underTest =
CommunalViewModel(
kosmos.testDispatcher,
@@ -164,7 +170,7 @@ class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() {
kosmos.keyguardInteractor,
mock<KeyguardIndicationController>(),
kosmos.communalSceneInteractor,
- kosmos.communalInteractor,
+ communalInteractor,
kosmos.communalSettingsInteractor,
kosmos.communalTutorialInteractor,
kosmos.shadeInteractor,
@@ -222,11 +228,15 @@ class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() {
widgetRepository.setCommunalWidgets(widgets)
// Smartspace available.
- val target = Mockito.mock(SmartspaceTarget::class.java)
- whenever(target.smartspaceTargetId).thenReturn("target")
- whenever(target.featureType).thenReturn(SmartspaceTarget.FEATURE_TIMER)
- whenever(target.remoteViews).thenReturn(Mockito.mock(RemoteViews::class.java))
- smartspaceRepository.setCommunalSmartspaceTargets(listOf(target))
+ smartspaceRepository.setTimers(
+ listOf(
+ CommunalSmartspaceTimer(
+ smartspaceTargetId = "target",
+ createdTimestampMillis = 0L,
+ remoteViews = Mockito.mock(RemoteViews::class.java),
+ )
+ )
+ )
// Media playing.
mediaRepository.mediaActive()
@@ -293,7 +303,7 @@ class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() {
widgetRepository.setCommunalWidgets(emptyList())
// UMO playing
mediaRepository.mediaActive()
- smartspaceRepository.setCommunalSmartspaceTargets(emptyList())
+ smartspaceRepository.setTimers(emptyList())
val isEmptyState by collectLastValue(underTest.isEmptyState)
assertThat(isEmptyState).isTrue()
@@ -314,7 +324,7 @@ class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() {
),
)
mediaRepository.mediaInactive()
- smartspaceRepository.setCommunalSmartspaceTargets(emptyList())
+ smartspaceRepository.setTimers(emptyList())
val isEmptyState by collectLastValue(underTest.isEmptyState)
assertThat(isEmptyState).isFalse()
@@ -689,11 +699,15 @@ class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() {
advanceTimeBy(60L)
// New timer available
- val target = Mockito.mock(SmartspaceTarget::class.java)
- whenever<String?>(target.smartspaceTargetId).thenReturn("target")
- whenever(target.featureType).thenReturn(SmartspaceTarget.FEATURE_TIMER)
- whenever(target.remoteViews).thenReturn(Mockito.mock(RemoteViews::class.java))
- smartspaceRepository.setCommunalSmartspaceTargets(listOf(target))
+ smartspaceRepository.setTimers(
+ listOf(
+ CommunalSmartspaceTimer(
+ smartspaceTargetId = "target",
+ createdTimestampMillis = 0L,
+ remoteViews = Mockito.mock(RemoteViews::class.java),
+ )
+ )
+ )
runCurrent()
// Still only emits widgets and the CTA tile
@@ -748,11 +762,15 @@ class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() {
assertThat(communalContent).hasSize(3)
// When new timer available
- val target = Mockito.mock(SmartspaceTarget::class.java)
- whenever(target.smartspaceTargetId).thenReturn("target")
- whenever(target.featureType).thenReturn(SmartspaceTarget.FEATURE_TIMER)
- whenever(target.remoteViews).thenReturn(Mockito.mock(RemoteViews::class.java))
- smartspaceRepository.setCommunalSmartspaceTargets(listOf(target))
+ smartspaceRepository.setTimers(
+ listOf(
+ CommunalSmartspaceTimer(
+ smartspaceTargetId = "target",
+ createdTimestampMillis = 0L,
+ remoteViews = Mockito.mock(RemoteViews::class.java),
+ )
+ )
+ )
runCurrent()
// Then emits timer, widgets and the CTA tile
@@ -767,6 +785,16 @@ class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() {
.isInstanceOf(CommunalContentModel.CtaTileInViewMode::class.java)
}
+ @Test
+ fun scrollPosition_persistedOnEditEntry() {
+ val index = 2
+ val offset = 30
+ underTest.onScrollPositionUpdated(index, offset)
+ underTest.onOpenWidgetEditor(false)
+
+ verify(communalInteractor).setScrollPosition(eq(index), eq(offset))
+ }
+
private suspend fun setIsMainUser(isMainUser: Boolean) {
val user = if (isMainUser) MAIN_USER_INFO else SECONDARY_USER_INFO
with(userRepository) {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt
index 5a39de8392be..444f63afb021 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt
@@ -34,6 +34,9 @@ import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LifecycleRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
+import com.android.app.viewcapture.ViewCapture
+import com.android.app.viewcapture.ViewCaptureAwareWindowManager
+import com.android.app.viewcapture.ViewCaptureFactory
import com.android.compose.animation.scene.ObservableTransitionState
import com.android.internal.logging.UiEventLogger
import com.android.keyguard.KeyguardUpdateMonitor
@@ -79,6 +82,7 @@ import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.Mockito.clearInvocations
import org.mockito.Mockito.isNull
+import org.mockito.Mockito.spy
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
@@ -114,11 +118,11 @@ class DreamOverlayServiceTest : SysuiTestCase() {
@Mock
lateinit var mDreamComplicationComponentFactory:
- com.android.systemui.dreams.complication.dagger.ComplicationComponent.Factory
+ com.android.systemui.dreams.complication.dagger.ComplicationComponent.Factory
@Mock
lateinit var mDreamComplicationComponent:
- com.android.systemui.dreams.complication.dagger.ComplicationComponent
+ com.android.systemui.dreams.complication.dagger.ComplicationComponent
@Mock lateinit var mHideComplicationTouchHandler: HideComplicationTouchHandler
@@ -154,8 +158,12 @@ class DreamOverlayServiceTest : SysuiTestCase() {
@Mock lateinit var mDreamOverlayCallbackController: DreamOverlayCallbackController
+ @Mock lateinit var mLazyViewCapture: Lazy<ViewCapture>
+
+ private lateinit var mViewCaptureAwareWindowManager: ViewCaptureAwareWindowManager
private lateinit var bouncerRepository: FakeKeyguardBouncerRepository
private lateinit var communalRepository: FakeCommunalSceneRepository
+ private var viewCaptureSpy = spy(ViewCaptureFactory.getInstance(context))
@Captor var mViewCaptor: ArgumentCaptor<View>? = null
private lateinit var mService: DreamOverlayService
@@ -192,13 +200,16 @@ class DreamOverlayServiceTest : SysuiTestCase() {
whenever(mDreamOverlayContainerViewController.containerView)
.thenReturn(mDreamOverlayContainerView)
whenever(mScrimManager.getCurrentController()).thenReturn(mScrimController)
+ whenever(mLazyViewCapture.value).thenReturn(viewCaptureSpy)
mWindowParams = WindowManager.LayoutParams()
+ mViewCaptureAwareWindowManager = ViewCaptureAwareWindowManager(mWindowManager,
+ mLazyViewCapture, isViewCaptureEnabled = false)
mService =
DreamOverlayService(
mContext,
mLifecycleOwner,
mMainExecutor,
- mWindowManager,
+ mViewCaptureAwareWindowManager,
mComplicationComponentFactory,
mDreamComplicationComponentFactory,
mDreamOverlayComponentFactory,
@@ -246,7 +257,7 @@ class DreamOverlayServiceTest : SysuiTestCase() {
mMainExecutor.runAllReady()
verify(mUiEventLogger).log(DreamOverlayService.DreamOverlayEvent.DREAM_OVERLAY_ENTER_START)
verify(mUiEventLogger)
- .log(DreamOverlayService.DreamOverlayEvent.DREAM_OVERLAY_COMPLETE_START)
+ .log(DreamOverlayService.DreamOverlayEvent.DREAM_OVERLAY_COMPLETE_START)
}
@Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/qs/QSLongPressEffectTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/qs/QSLongPressEffectTest.kt
index 74eee9b24cbc..693fcdabea58 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/qs/QSLongPressEffectTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/qs/QSLongPressEffectTest.kt
@@ -17,10 +17,12 @@
package com.android.systemui.haptics.qs
import android.os.VibrationEffect
+import android.service.quicksettings.Tile
import android.testing.TestableLooper.RunWithLooper
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.classifier.falsingManager
import com.android.systemui.haptics.vibratorHelper
import com.android.systemui.kosmos.testScope
import com.android.systemui.qs.qsTileFactory
@@ -69,6 +71,7 @@ class QSLongPressEffectTest : SysuiTestCase() {
QSLongPressEffect(
vibratorHelper,
kosmos.keyguardStateController,
+ kosmos.falsingManager,
)
longPressEffect.callback = callback
longPressEffect.qsTile = qsTile
@@ -175,17 +178,17 @@ class QSLongPressEffectTest : SysuiTestCase() {
}
@Test
- fun onAnimationComplete_keyguardDismissible_effectCompletes() =
+ fun onAnimationComplete_keyguardDismissible_effectEndsInLongClicked() =
testWhileInState(QSLongPressEffect.State.RUNNING_FORWARD) {
// GIVEN that the animation completes
longPressEffect.handleAnimationComplete()
- // THEN the long-press effect completes
- assertEffectCompleted()
+ // THEN the long-press effect completes with a long-click state
+ assertEffectCompleted(QSLongPressEffect.State.LONG_CLICKED)
}
@Test
- fun onAnimationComplete_keyguardNotDismissible_effectEndsWithReset() =
+ fun onAnimationComplete_keyguardNotDismissible_effectEndsInIdleWithReset() =
testWhileInState(QSLongPressEffect.State.RUNNING_FORWARD) {
// GIVEN that the keyguard is not dismissible
whenever(kosmos.keyguardStateController.isUnlocked).thenReturn(false)
@@ -193,19 +196,20 @@ class QSLongPressEffectTest : SysuiTestCase() {
// GIVEN that the animation completes
longPressEffect.handleAnimationComplete()
- // THEN the long-press effect completes and the properties are called to reset
- assertEffectCompleted()
+ // THEN the long-press effect ends in the idle state and the properties are reset
+ assertEffectCompleted(QSLongPressEffect.State.IDLE)
verify(callback, times(1)).onResetProperties()
}
@Test
- fun onAnimationComplete_whenRunningBackwardsFromUp_endsWithFinishedReversing() =
+ fun onAnimationComplete_whenRunningBackwardsFromUp_endsWithFinishedReversingAndClick() =
testWhileInState(QSLongPressEffect.State.RUNNING_BACKWARDS_FROM_UP) {
// GIVEN that the animation completes
longPressEffect.handleAnimationComplete()
- // THEN the callback for finished reversing is used.
+ // THEN the callback for finished reversing is used and the effect ends with a click.
verify(callback, times(1)).onEffectFinishedReversing()
+ assertThat(longPressEffect.state).isEqualTo(QSLongPressEffect.State.CLICKED)
}
@Test
@@ -262,18 +266,88 @@ class QSLongPressEffectTest : SysuiTestCase() {
}
@Test
- fun onTileClick_whileWaiting_withoutQSTile_cannotClick() =
- testWhileInState(QSLongPressEffect.State.TIMEOUT_WAIT) {
- // GIVEN that no QSTile has been set
- longPressEffect.qsTile = null
-
+ fun onTileClick_whileIdle_withQSTile_clicks() =
+ testWhileInState(QSLongPressEffect.State.IDLE) {
// GIVEN that a click was detected
val couldClick = longPressEffect.onTileClick()
+ // THEN the click is successful
+ assertThat(couldClick).isTrue()
+ }
+
+ @Test
+ fun onTileClick_whenBouncerIsShowing_ignoresClick() =
+ testWhileInState(QSLongPressEffect.State.IDLE) {
+ // GIVEN that the bouncer is showing
+ whenever(kosmos.keyguardStateController.isPrimaryBouncerShowing).thenReturn(true)
+
+ // WHEN a click is detected by the tile view
+ val couldClick = longPressEffect.onTileClick()
+
// THEN the click is not successful
assertThat(couldClick).isFalse()
}
+ @Test
+ fun getStateForClick_withUnavailableTile_returnsIdle() {
+ // GIVEN an unavailable tile
+ qsTile.state?.state = Tile.STATE_UNAVAILABLE
+
+ // WHEN determining the state of a click action
+ val clickState = longPressEffect.getStateForClick()
+
+ // THEN the state is IDLE
+ assertThat(clickState).isEqualTo(QSLongPressEffect.State.IDLE)
+ }
+
+ @Test
+ fun getStateForClick_withFalseTapWhenLocked_returnsIdle() {
+ // GIVEN an active tile
+ qsTile.state?.state = Tile.STATE_ACTIVE
+
+ // GIVEN that the device is locked and a false tap is detected
+ whenever(kosmos.keyguardStateController.isUnlocked).thenReturn(false)
+ kosmos.falsingManager.setFalseTap(true)
+
+ // WHEN determining the state of a click action
+ val clickState = longPressEffect.getStateForClick()
+
+ // THEN the state is IDLE
+ assertThat(clickState).isEqualTo(QSLongPressEffect.State.IDLE)
+ }
+
+ @Test
+ fun getStateForClick_withValidTapAndTile_returnsClicked() {
+ // GIVEN an active tile
+ qsTile.state?.state = Tile.STATE_ACTIVE
+
+ // GIVEN that the device is locked and a false tap is not detected
+ whenever(kosmos.keyguardStateController.isUnlocked).thenReturn(false)
+ kosmos.falsingManager.setFalseTap(false)
+
+ // WHEN determining the state of a click action
+ val clickState = longPressEffect.getStateForClick()
+
+ // THEN the state is CLICKED
+ assertThat(clickState).isEqualTo(QSLongPressEffect.State.CLICKED)
+ }
+
+ @Test
+ fun getStateForClick_withNullTile_returnsIdle() {
+ // GIVEN that the tile is null
+ longPressEffect.qsTile = null
+
+ // GIVEN that the device is locked and a false tap is not detected
+ whenever(kosmos.keyguardStateController.isUnlocked).thenReturn(false)
+ kosmos.falsingManager.setFalseTap(false)
+
+ // WHEN determining the state of a click action
+ val clickState = longPressEffect.getStateForClick()
+
+ // THEN the state is IDLE
+ assertThat(clickState).isEqualTo(QSLongPressEffect.State.IDLE)
+ }
+
private fun testWithScope(initialize: Boolean = true, test: suspend TestScope.() -> Unit) =
with(kosmos) {
testScope.runTest {
@@ -339,14 +413,14 @@ class QSLongPressEffectTest : SysuiTestCase() {
/**
* Asserts that the effect completes by checking that:
* 1. The final snap haptics are played
- * 2. The internal state goes back to [QSLongPressEffect.State.IDLE]
+ * 2. The internal state goes back to specified end state.
*/
- private fun assertEffectCompleted() {
+ private fun assertEffectCompleted(endState: QSLongPressEffect.State) {
val snapEffect = LongPressHapticBuilder.createSnapEffect()
assertThat(snapEffect).isNotNull()
assertThat(vibratorHelper.hasVibratedWithEffects(snapEffect!!)).isTrue()
- assertThat(longPressEffect.state).isEqualTo(QSLongPressEffect.State.IDLE)
+ assertThat(longPressEffect.state).isEqualTo(endState)
}
/**
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractorTest.kt
index 612f2e73e4bb..ec4fd79b399a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractorTest.kt
@@ -34,12 +34,14 @@ package com.android.systemui.keyguard.domain.interactor
import android.os.PowerManager
import android.platform.test.annotations.EnableFlags
+import android.service.dream.dreamManager
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.compose.animation.scene.ObservableTransitionState
import com.android.systemui.Flags
import com.android.systemui.SysuiTestCase
import com.android.systemui.communal.data.repository.fakeCommunalSceneRepository
+import com.android.systemui.communal.domain.interactor.setCommunalAvailable
import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
@@ -64,8 +66,10 @@ import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.Mockito.anyBoolean
import org.mockito.Mockito.reset
import org.mockito.Mockito.spy
+import org.mockito.kotlin.whenever
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@@ -120,6 +124,66 @@ class FromDozingTransitionInteractorTest : SysuiTestCase() {
@Test
@EnableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR)
+ fun testTransitionToLockscreen_onPowerButtonPress_canDream_glanceableHubAvailable() =
+ testScope.runTest {
+ whenever(kosmos.dreamManager.canStartDreaming(anyBoolean())).thenReturn(true)
+ kosmos.setCommunalAvailable(true)
+ runCurrent()
+
+ powerInteractor.setAwakeForTest(reason = PowerManager.WAKE_REASON_POWER_BUTTON)
+ runCurrent()
+
+ // If dreaming is possible and communal is available, then we should transition to
+ // GLANCEABLE_HUB when waking up due to power button press.
+ assertThat(transitionRepository)
+ .startedTransition(
+ from = KeyguardState.DOZING,
+ to = KeyguardState.GLANCEABLE_HUB,
+ )
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR)
+ fun testTransitionToLockscreen_onPowerButtonPress_canNotDream_glanceableHubAvailable() =
+ testScope.runTest {
+ whenever(kosmos.dreamManager.canStartDreaming(anyBoolean())).thenReturn(false)
+ kosmos.setCommunalAvailable(true)
+ runCurrent()
+
+ powerInteractor.setAwakeForTest(reason = PowerManager.WAKE_REASON_POWER_BUTTON)
+ runCurrent()
+
+ // If dreaming is NOT possible but communal is available, then we should transition to
+ // LOCKSCREEN when waking up due to power button press.
+ assertThat(transitionRepository)
+ .startedTransition(
+ from = KeyguardState.DOZING,
+ to = KeyguardState.LOCKSCREEN,
+ )
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR)
+ fun testTransitionToLockscreen_onPowerButtonPress_canNDream_glanceableHubNotAvailable() =
+ testScope.runTest {
+ whenever(kosmos.dreamManager.canStartDreaming(anyBoolean())).thenReturn(true)
+ kosmos.setCommunalAvailable(false)
+ runCurrent()
+
+ powerInteractor.setAwakeForTest(reason = PowerManager.WAKE_REASON_POWER_BUTTON)
+ runCurrent()
+
+ // If dreaming is possible but communal is NOT available, then we should transition to
+ // LOCKSCREEN when waking up due to power button press.
+ assertThat(transitionRepository)
+ .startedTransition(
+ from = KeyguardState.DOZING,
+ to = KeyguardState.LOCKSCREEN,
+ )
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR)
fun testTransitionToGlanceableHub_onWakeup_ifIdleOnCommunal_noOccludingActivity() =
testScope.runTest {
kosmos.fakeCommunalSceneRepository.setTransitionState(
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractorTest.kt
index 26b56a1be926..48621047016b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractorTest.kt
@@ -37,7 +37,6 @@ import com.android.systemui.kosmos.testScope
import com.android.systemui.media.controls.data.repository.mediaFilterRepository
import com.android.systemui.media.controls.shared.model.MediaData
import com.android.systemui.shade.data.repository.shadeRepository
-import com.android.systemui.shade.shared.model.ShadeMode
import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository
import com.android.systemui.statusbar.notification.data.repository.setActiveNotifs
import com.android.systemui.statusbar.notification.stack.data.repository.headsUpNotificationRepository
@@ -81,10 +80,10 @@ class KeyguardClockInteractorTest : SysuiTestCase() {
testScope.runTest {
val value by collectLastValue(underTest.clockShouldBeCentered)
kosmos.keyguardInteractor.setClockShouldBeCentered(true)
- assertThat(value).isEqualTo(true)
+ assertThat(value).isTrue()
kosmos.keyguardInteractor.setClockShouldBeCentered(false)
- assertThat(value).isEqualTo(false)
+ assertThat(value).isFalse()
}
@Test
@@ -103,7 +102,7 @@ class KeyguardClockInteractorTest : SysuiTestCase() {
fun clockSize_SceneContainerFlagOn_shadeModeSingle_hasNotifs_SMALL() =
testScope.runTest {
val value by collectLastValue(underTest.clockSize)
- kosmos.shadeRepository.setShadeMode(ShadeMode.Single)
+ kosmos.shadeRepository.setShadeLayoutWide(false)
kosmos.activeNotificationListRepository.setActiveNotifs(1)
assertThat(value).isEqualTo(ClockSize.SMALL)
}
@@ -113,7 +112,7 @@ class KeyguardClockInteractorTest : SysuiTestCase() {
fun clockSize_SceneContainerFlagOn_shadeModeSingle_hasMedia_SMALL() =
testScope.runTest {
val value by collectLastValue(underTest.clockSize)
- kosmos.shadeRepository.setShadeMode(ShadeMode.Single)
+ kosmos.shadeRepository.setShadeLayoutWide(false)
val userMedia = MediaData().copy(active = true)
kosmos.mediaFilterRepository.addSelectedUserMediaEntry(userMedia)
assertThat(value).isEqualTo(ClockSize.SMALL)
@@ -125,7 +124,7 @@ class KeyguardClockInteractorTest : SysuiTestCase() {
testScope.runTest {
val value by collectLastValue(underTest.clockSize)
val userMedia = MediaData().copy(active = true)
- kosmos.shadeRepository.setShadeMode(ShadeMode.Split)
+ kosmos.shadeRepository.setShadeLayoutWide(true)
kosmos.mediaFilterRepository.addSelectedUserMediaEntry(userMedia)
kosmos.keyguardRepository.setIsDozing(false)
assertThat(value).isEqualTo(ClockSize.SMALL)
@@ -136,7 +135,7 @@ class KeyguardClockInteractorTest : SysuiTestCase() {
fun clockSize_SceneContainerFlagOn_shadeModeSplit_noMedia_LARGE() =
testScope.runTest {
val value by collectLastValue(underTest.clockSize)
- kosmos.shadeRepository.setShadeMode(ShadeMode.Split)
+ kosmos.shadeRepository.setShadeLayoutWide(true)
kosmos.keyguardRepository.setIsDozing(false)
assertThat(value).isEqualTo(ClockSize.LARGE)
}
@@ -147,7 +146,7 @@ class KeyguardClockInteractorTest : SysuiTestCase() {
testScope.runTest {
val value by collectLastValue(underTest.clockSize)
val userMedia = MediaData().copy(active = true)
- kosmos.shadeRepository.setShadeMode(ShadeMode.Split)
+ kosmos.shadeRepository.setShadeLayoutWide(true)
kosmos.mediaFilterRepository.addSelectedUserMediaEntry(userMedia)
kosmos.keyguardRepository.setIsDozing(true)
assertThat(value).isEqualTo(ClockSize.LARGE)
@@ -158,8 +157,8 @@ class KeyguardClockInteractorTest : SysuiTestCase() {
fun clockShouldBeCentered_sceneContainerFlagOn_notSplitMode_true() =
testScope.runTest {
val value by collectLastValue(underTest.clockShouldBeCentered)
- kosmos.shadeRepository.setShadeMode(ShadeMode.Single)
- assertThat(value).isEqualTo(true)
+ kosmos.shadeRepository.setShadeLayoutWide(false)
+ assertThat(value).isTrue()
}
@Test
@@ -167,9 +166,9 @@ class KeyguardClockInteractorTest : SysuiTestCase() {
fun clockShouldBeCentered_sceneContainerFlagOn_splitMode_noActiveNotifications_true() =
testScope.runTest {
val value by collectLastValue(underTest.clockShouldBeCentered)
- kosmos.shadeRepository.setShadeMode(ShadeMode.Split)
+ kosmos.shadeRepository.setShadeLayoutWide(true)
kosmos.activeNotificationListRepository.setActiveNotifs(0)
- assertThat(value).isEqualTo(true)
+ assertThat(value).isTrue()
}
@Test
@@ -177,10 +176,10 @@ class KeyguardClockInteractorTest : SysuiTestCase() {
fun clockShouldBeCentered_sceneContainerFlagOn_splitMode_isActiveDreamLockscreenHosted_true() =
testScope.runTest {
val value by collectLastValue(underTest.clockShouldBeCentered)
- kosmos.shadeRepository.setShadeMode(ShadeMode.Split)
+ kosmos.shadeRepository.setShadeLayoutWide(true)
kosmos.activeNotificationListRepository.setActiveNotifs(1)
kosmos.keyguardRepository.setIsActiveDreamLockscreenHosted(true)
- assertThat(value).isEqualTo(true)
+ assertThat(value).isTrue()
}
@Test
@@ -188,11 +187,11 @@ class KeyguardClockInteractorTest : SysuiTestCase() {
fun clockShouldBeCentered_sceneContainerFlagOn_splitMode_hasPulsingNotifications_false() =
testScope.runTest {
val value by collectLastValue(underTest.clockShouldBeCentered)
- kosmos.shadeRepository.setShadeMode(ShadeMode.Split)
+ kosmos.shadeRepository.setShadeLayoutWide(true)
kosmos.activeNotificationListRepository.setActiveNotifs(1)
kosmos.headsUpNotificationRepository.isHeadsUpAnimatingAway.value = true
kosmos.keyguardRepository.setIsDozing(true)
- assertThat(value).isEqualTo(false)
+ assertThat(value).isFalse()
}
@Test
@@ -200,10 +199,10 @@ class KeyguardClockInteractorTest : SysuiTestCase() {
fun clockShouldBeCentered_sceneContainerFlagOn_splitMode_onAod_true() =
testScope.runTest {
val value by collectLastValue(underTest.clockShouldBeCentered)
- kosmos.shadeRepository.setShadeMode(ShadeMode.Split)
+ kosmos.shadeRepository.setShadeLayoutWide(true)
kosmos.activeNotificationListRepository.setActiveNotifs(1)
transitionTo(KeyguardState.LOCKSCREEN, KeyguardState.AOD)
- assertThat(value).isEqualTo(true)
+ assertThat(value).isTrue()
}
@Test
@@ -211,10 +210,10 @@ class KeyguardClockInteractorTest : SysuiTestCase() {
fun clockShouldBeCentered_sceneContainerFlagOn_splitMode_offAod_false() =
testScope.runTest {
val value by collectLastValue(underTest.clockShouldBeCentered)
- kosmos.shadeRepository.setShadeMode(ShadeMode.Split)
+ kosmos.shadeRepository.setShadeLayoutWide(true)
kosmos.activeNotificationListRepository.setActiveNotifs(1)
transitionTo(KeyguardState.AOD, KeyguardState.LOCKSCREEN)
- assertThat(value).isEqualTo(false)
+ assertThat(value).isFalse()
}
private suspend fun transitionTo(from: KeyguardState, to: KeyguardState) {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModelTest.kt
index 875e9e0210fb..50772eedc914 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModelTest.kt
@@ -37,7 +37,6 @@ import com.android.systemui.res.R
import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.data.repository.shadeRepository
-import com.android.systemui.shade.shared.model.ShadeMode
import com.android.systemui.testKosmos
import com.android.systemui.unfold.fakeUnfoldTransitionProgressProvider
import com.android.systemui.util.mockito.whenever
@@ -76,7 +75,7 @@ class LockscreenContentViewModelTest(flags: FlagsParameterization) : SysuiTestCa
fun setup() {
with(kosmos) {
fakeFeatureFlagsClassic.set(Flags.LOCK_SCREEN_LONG_PRESS_ENABLED, true)
- shadeRepository.setShadeMode(ShadeMode.Single)
+ shadeRepository.setShadeLayoutWide(false)
underTest = lockscreenContentViewModel
}
}
@@ -126,7 +125,7 @@ class LockscreenContentViewModelTest(flags: FlagsParameterization) : SysuiTestCa
with(kosmos) {
testScope.runTest {
val areNotificationsVisible by collectLastValue(underTest.areNotificationsVisible)
- shadeRepository.setShadeMode(ShadeMode.Split)
+ shadeRepository.setShadeLayoutWide(true)
fakeKeyguardClockRepository.setClockSize(ClockSize.LARGE)
assertThat(areNotificationsVisible).isTrue()
@@ -156,24 +155,24 @@ class LockscreenContentViewModelTest(flags: FlagsParameterization) : SysuiTestCa
}
@Test
- fun shouldUseSplitNotificationShade_withConfigTrue_true() =
+ fun isShadeLayoutWide_withConfigTrue_true() =
with(kosmos) {
testScope.runTest {
- val shouldUseSplitNotificationShade by
- collectLastValue(underTest.shouldUseSplitNotificationShade)
- shadeRepository.setShadeMode(ShadeMode.Split)
- assertThat(shouldUseSplitNotificationShade).isTrue()
+ val isShadeLayoutWide by collectLastValue(underTest.isShadeLayoutWide)
+ shadeRepository.setShadeLayoutWide(true)
+
+ assertThat(isShadeLayoutWide).isTrue()
}
}
@Test
- fun shouldUseSplitNotificationShade_withConfigFalse_false() =
+ fun isShadeLayoutWide_withConfigFalse_false() =
with(kosmos) {
testScope.runTest {
- val shouldUseSplitNotificationShade by
- collectLastValue(underTest.shouldUseSplitNotificationShade)
- shadeRepository.setShadeMode(ShadeMode.Single)
- assertThat(shouldUseSplitNotificationShade).isFalse()
+ val isShadeLayoutWide by collectLastValue(underTest.isShadeLayoutWide)
+ shadeRepository.setShadeLayoutWide(false)
+
+ assertThat(isShadeLayoutWide).isFalse()
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt
index 4eb146dbbaba..3db9ef1eca71 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt
@@ -44,7 +44,6 @@ import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.shared.model.TransitionKeys
import com.android.systemui.shade.data.repository.shadeRepository
import com.android.systemui.shade.domain.interactor.shadeInteractor
-import com.android.systemui.shade.shared.model.ShadeMode
import com.android.systemui.statusbar.notification.stack.ui.viewmodel.notificationsPlaceholderViewModel
import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.mock
@@ -182,13 +181,7 @@ class LockscreenSceneViewModelTest : SysuiTestCase() {
}
)
sceneInteractor.changeScene(Scenes.Lockscreen, "reason")
- kosmos.shadeRepository.setShadeMode(
- if (isSingleShade) {
- ShadeMode.Single
- } else {
- ShadeMode.Split
- }
- )
+ kosmos.shadeRepository.setShadeLayoutWide(!isSingleShade)
kosmos.setCommunalAvailable(isCommunalAvailable)
kosmos.fakePowerRepository.updateWakefulness(
rawState =
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModelTest.kt
index 0551bfb89865..067b00c1658b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModelTest.kt
@@ -33,13 +33,14 @@ import com.android.systemui.media.controls.domain.pipeline.MediaDataFilterImpl
import com.android.systemui.media.controls.domain.pipeline.interactor.mediaCarouselInteractor
import com.android.systemui.media.controls.domain.pipeline.interactor.mediaRecommendationsInteractor
import com.android.systemui.media.controls.domain.pipeline.mediaDataFilter
+import com.android.systemui.media.controls.shared.mediaLogger
+import com.android.systemui.media.controls.shared.mockMediaLogger
import com.android.systemui.media.controls.shared.model.MediaData
import com.android.systemui.media.controls.shared.model.SmartspaceMediaData
import com.android.systemui.statusbar.notification.collection.provider.visualStabilityProvider
import com.android.systemui.statusbar.notificationLockscreenUserManager
import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.any
-import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.runTest
@@ -48,12 +49,16 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers
import org.mockito.Mockito
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.never
+import org.mockito.kotlin.reset
+import org.mockito.kotlin.verify
@SmallTest
@RunWith(AndroidJUnit4::class)
class MediaCarouselViewModelTest : SysuiTestCase() {
- private val kosmos = testKosmos()
+ private val kosmos = testKosmos().apply { mediaLogger = mockMediaLogger }
private val testScope = kosmos.testScope
private val mediaDataFilter: MediaDataFilterImpl = kosmos.mediaDataFilter
@@ -166,6 +171,64 @@ class MediaCarouselViewModelTest : SysuiTestCase() {
assertThat(mediaControl.isMediaFromRec).isTrue()
}
+ @Test
+ fun addMediaControlThenRemove_mediaEventsAreLogged() =
+ testScope.runTest {
+ val sortedMedia by collectLastValue(underTest.mediaItems)
+ val instanceId = InstanceId.fakeInstanceId(123)
+
+ loadMediaControl(KEY, instanceId)
+
+ val mediaControl = sortedMedia?.get(0) as MediaCommonViewModel.MediaControl
+ assertThat(mediaControl.instanceId).isEqualTo(instanceId)
+
+ // when media control is added to carousel
+ mediaControl.onAdded(mediaControl)
+
+ verify(kosmos.mediaLogger).logMediaCardAdded(eq(instanceId))
+
+ reset(kosmos.mediaLogger)
+
+ // when media control is updated.
+ mediaControl.onUpdated(mediaControl)
+
+ verify(kosmos.mediaLogger, never()).logMediaCardAdded(eq(instanceId))
+
+ mediaDataFilter.onMediaDataRemoved(KEY, true)
+ assertThat(sortedMedia).isEmpty()
+
+ // when media control is removed from carousel
+ mediaControl.onRemoved(true)
+
+ verify(kosmos.mediaLogger).logMediaCardRemoved(eq(instanceId))
+ }
+
+ @Test
+ fun addMediaRecommendationThenRemove_mediaEventsAreLogged() =
+ testScope.runTest {
+ val sortedMedia by collectLastValue(underTest.mediaItems)
+ kosmos.fakeFeatureFlagsClassic.set(Flags.MEDIA_RETAIN_RECOMMENDATIONS, false)
+
+ loadMediaRecommendations()
+
+ val mediaRecommendations =
+ sortedMedia?.get(0) as MediaCommonViewModel.MediaRecommendations
+ assertThat(mediaRecommendations.key).isEqualTo(KEY_MEDIA_SMARTSPACE)
+
+ // when media recommendation is added to carousel
+ mediaRecommendations.onAdded(mediaRecommendations)
+
+ verify(kosmos.mediaLogger).logMediaRecommendationCardAdded(eq(KEY_MEDIA_SMARTSPACE))
+
+ mediaDataFilter.onSmartspaceMediaDataRemoved(KEY, true)
+ assertThat(sortedMedia).isEmpty()
+
+ // when media recommendation is removed from carousel
+ mediaRecommendations.onRemoved(true)
+
+ verify(kosmos.mediaLogger).logMediaRecommendationCardRemoved(eq(KEY_MEDIA_SMARTSPACE))
+ }
+
private fun loadMediaControl(key: String, instanceId: InstanceId, isPlaying: Boolean = true) {
whenever(notificationLockscreenUserManager.isCurrentProfile(USER_ID)).thenReturn(true)
whenever(notificationLockscreenUserManager.isProfileAvailable(USER_ID)).thenReturn(true)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/SettingObserverTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/SettingObserverTest.kt
new file mode 100644
index 000000000000..188f2aca5147
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/SettingObserverTest.kt
@@ -0,0 +1,117 @@
+/*
+ * 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
+
+import android.net.Uri
+import android.os.Handler
+import android.os.Looper
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.Flags
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.settings.SettingsProxy
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Captor
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.any
+import org.mockito.kotlin.capture
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.reset
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class SettingObserverTest : SysuiTestCase() {
+
+ private val DEFAULT_VALUE = 7
+
+ @Mock lateinit var settingsProxy: SettingsProxy
+ @Captor private lateinit var argumentCaptor: ArgumentCaptor<Runnable>
+
+ private lateinit var testSettingObserver: SettingObserver
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ whenever(settingsProxy.getInt(any(), any())).thenReturn(5)
+ whenever(settingsProxy.getUriFor(any())).thenReturn(Uri.parse("content://test_uri"))
+ testSettingObserver =
+ object :
+ SettingObserver(
+ settingsProxy,
+ Handler(Looper.getMainLooper()),
+ "test_setting",
+ DEFAULT_VALUE
+ ) {
+ override fun handleValueChanged(value: Int, observedChange: Boolean) {}
+ }
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_QS_REGISTER_SETTING_OBSERVER_ON_BG_THREAD)
+ fun setListening_true_settingsProxyRegistered() {
+ testSettingObserver.isListening = true
+ verify(settingsProxy)
+ .registerContentObserverAsync(
+ any<Uri>(),
+ eq(false),
+ eq(testSettingObserver),
+ capture(argumentCaptor)
+ )
+ assertThat(testSettingObserver.value).isEqualTo(5)
+
+ // Verify if the callback applies updated value after the fact
+ whenever(settingsProxy.getInt(any(), any())).thenReturn(12341234)
+ argumentCaptor.value.run()
+ assertThat(testSettingObserver.value).isEqualTo(12341234)
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_QS_REGISTER_SETTING_OBSERVER_ON_BG_THREAD)
+ fun setListening_false_settingsProxyRegistered() {
+ testSettingObserver.isListening = true
+ reset(settingsProxy)
+ testSettingObserver.isListening = false
+
+ verify(settingsProxy).unregisterContentObserverAsync(eq(testSettingObserver))
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_QS_REGISTER_SETTING_OBSERVER_ON_BG_THREAD)
+ fun setListening_bgFlagDisabled_true_settingsProxyRegistered() {
+ testSettingObserver.isListening = true
+ verify(settingsProxy)
+ .registerContentObserverSync(any<Uri>(), eq(false), eq(testSettingObserver))
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_QS_REGISTER_SETTING_OBSERVER_ON_BG_THREAD)
+ fun setListening_bgFlagDisabled_false_settingsProxyRegistered() {
+ testSettingObserver.isListening = true
+ reset(settingsProxy)
+ testSettingObserver.isListening = false
+
+ verify(settingsProxy).unregisterContentObserverSync(eq(testSettingObserver))
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/data/repository/QSPreferencesRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/data/repository/QSPreferencesRepositoryTest.kt
index 8ac5b6c09e73..dda9cd5529a5 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/data/repository/QSPreferencesRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/data/repository/QSPreferencesRepositoryTest.kt
@@ -24,6 +24,7 @@ import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.kosmos.testScope
+import com.android.systemui.qs.pipeline.shared.TileSpec
import com.android.systemui.settings.userFileManager
import com.android.systemui.testKosmos
import com.android.systemui.user.data.repository.fakeUserRepository
@@ -40,6 +41,70 @@ class QSPreferencesRepositoryTest : SysuiTestCase() {
private val underTest = with(kosmos) { qsPreferencesRepository }
@Test
+ fun largeTilesSpecs_updatesFromSharedPreferences() =
+ with(kosmos) {
+ testScope.runTest {
+ val latest by collectLastValue(underTest.largeTilesSpecs)
+ assertThat(latest).isEqualTo(defaultLargeTilesRepository.defaultLargeTiles)
+
+ val newSet = setOf("tileA", "tileB")
+ setLargeTilesSpecsInSharedPreferences(newSet)
+ assertThat(latest).isEqualTo(newSet.toTileSpecs())
+ }
+ }
+
+ @Test
+ fun largeTilesSpecs_updatesFromUserChange() =
+ with(kosmos) {
+ testScope.runTest {
+ fakeUserRepository.setUserInfos(USERS)
+ val latest by collectLastValue(underTest.largeTilesSpecs)
+
+ fakeUserRepository.setSelectedUserInfo(PRIMARY_USER)
+ val newSet = setOf("tileA", "tileB")
+ setLargeTilesSpecsInSharedPreferences(newSet)
+
+ fakeUserRepository.setSelectedUserInfo(ANOTHER_USER)
+ setLargeTilesSpecsInSharedPreferences(emptySet())
+
+ fakeUserRepository.setSelectedUserInfo(PRIMARY_USER)
+ assertThat(latest).isEqualTo(newSet.toTileSpecs())
+ }
+ }
+
+ @Test
+ fun setLargeTilesSpecs_inSharedPreferences() {
+ val setA = setOf("tileA", "tileB")
+ underTest.setLargeTilesSpecs(setA.toTileSpecs())
+ assertThat(getLargeTilesSpecsFromSharedPreferences()).isEqualTo(setA)
+
+ val setB = setOf("tileA", "tileB")
+ underTest.setLargeTilesSpecs(setB.toTileSpecs())
+ assertThat(getLargeTilesSpecsFromSharedPreferences()).isEqualTo(setB)
+ }
+
+ @Test
+ fun setLargeTilesSpecs_forDifferentUser() =
+ with(kosmos) {
+ testScope.runTest {
+ fakeUserRepository.setUserInfos(USERS)
+
+ fakeUserRepository.setSelectedUserInfo(PRIMARY_USER)
+ val setA = setOf("tileA", "tileB")
+ underTest.setLargeTilesSpecs(setA.toTileSpecs())
+ assertThat(getLargeTilesSpecsFromSharedPreferences()).isEqualTo(setA)
+
+ fakeUserRepository.setSelectedUserInfo(ANOTHER_USER)
+ val setB = setOf("tileA", "tileB")
+ underTest.setLargeTilesSpecs(setB.toTileSpecs())
+ assertThat(getLargeTilesSpecsFromSharedPreferences()).isEqualTo(setB)
+
+ fakeUserRepository.setSelectedUserInfo(PRIMARY_USER)
+ assertThat(getLargeTilesSpecsFromSharedPreferences()).isEqualTo(setA)
+ }
+ }
+
+ @Test
fun showLabels_updatesFromSharedPreferences() =
with(kosmos) {
testScope.runTest {
@@ -109,6 +174,14 @@ class QSPreferencesRepositoryTest : SysuiTestCase() {
)
}
+ private fun setLargeTilesSpecsInSharedPreferences(specs: Set<String>) {
+ getSharedPreferences().edit().putStringSet(LARGE_TILES_SPECS_KEY, specs).apply()
+ }
+
+ private fun getLargeTilesSpecsFromSharedPreferences(): Set<String> {
+ return getSharedPreferences().getStringSet(LARGE_TILES_SPECS_KEY, emptySet())!!
+ }
+
private fun setShowLabelsInSharedPreferences(value: Boolean) {
getSharedPreferences().edit().putBoolean(ICON_LABELS_KEY, value).apply()
}
@@ -117,8 +190,13 @@ class QSPreferencesRepositoryTest : SysuiTestCase() {
return getSharedPreferences().getBoolean(ICON_LABELS_KEY, defaultValue)
}
+ private fun Set<String>.toTileSpecs(): Set<TileSpec> {
+ return map { TileSpec.create(it) }.toSet()
+ }
+
companion object {
private const val ICON_LABELS_KEY = "show_icon_labels"
+ private const val LARGE_TILES_SPECS_KEY = "large_tiles_specs"
private const val PRIMARY_USER_ID = 0
private val PRIMARY_USER = UserInfo(PRIMARY_USER_ID, "user 0", UserInfo.FLAG_MAIN)
private const val ANOTHER_USER_ID = 1
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/domain/interactor/GridConsistencyInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/domain/interactor/GridConsistencyInteractorTest.kt
index b206f56f95a6..56b3679b6835 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/domain/interactor/GridConsistencyInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/domain/interactor/GridConsistencyInteractorTest.kt
@@ -20,9 +20,9 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.kosmos.testScope
-import com.android.systemui.qs.panels.data.repository.IconTilesRepository
+import com.android.systemui.qs.panels.data.repository.DefaultLargeTilesRepository
+import com.android.systemui.qs.panels.data.repository.defaultLargeTilesRepository
import com.android.systemui.qs.panels.data.repository.gridLayoutTypeRepository
-import com.android.systemui.qs.panels.data.repository.iconTilesRepository
import com.android.systemui.qs.panels.shared.model.InfiniteGridLayoutType
import com.android.systemui.qs.panels.shared.model.PartitionedGridLayoutType
import com.android.systemui.qs.pipeline.data.repository.tileSpecRepository
@@ -42,22 +42,17 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class GridConsistencyInteractorTest : SysuiTestCase() {
- private val iconOnlyTiles =
- setOf(
- TileSpec.create("smallA"),
- TileSpec.create("smallB"),
- TileSpec.create("smallC"),
- TileSpec.create("smallD"),
- TileSpec.create("smallE"),
- )
-
private val kosmos =
testKosmos().apply {
- iconTilesRepository =
- object : IconTilesRepository {
- override fun isIconTile(spec: TileSpec): Boolean {
- return iconOnlyTiles.contains(spec)
- }
+ defaultLargeTilesRepository =
+ object : DefaultLargeTilesRepository {
+ override val defaultLargeTiles =
+ setOf(
+ TileSpec.create("largeA"),
+ TileSpec.create("largeB"),
+ TileSpec.create("largeC"),
+ TileSpec.create("largeD"),
+ )
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/domain/interactor/IconTilesInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/domain/interactor/IconTilesInteractorTest.kt
new file mode 100644
index 000000000000..c3a5df06e2a4
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/domain/interactor/IconTilesInteractorTest.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.qs.panels.domain.interactor
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.qs.panels.data.repository.DefaultLargeTilesRepository
+import com.android.systemui.qs.panels.data.repository.defaultLargeTilesRepository
+import com.android.systemui.qs.panels.data.repository.qsPreferencesRepository
+import com.android.systemui.qs.pipeline.shared.TileSpec
+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.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class IconTilesInteractorTest : SysuiTestCase() {
+ private val kosmos =
+ testKosmos().apply {
+ defaultLargeTilesRepository =
+ object : DefaultLargeTilesRepository {
+ override val defaultLargeTiles: Set<TileSpec> = setOf(TileSpec.create("large"))
+ }
+ }
+ private val underTest = with(kosmos) { iconTilesInteractor }
+
+ @Test
+ fun isIconTile_returnsCorrectValue() {
+ assertThat(underTest.isIconTile(TileSpec.create("large"))).isFalse()
+ assertThat(underTest.isIconTile(TileSpec.create("small"))).isTrue()
+ }
+
+ @OptIn(ExperimentalCoroutinesApi::class)
+ @Test
+ fun isIconTile_updatesFromSharedPreferences() =
+ with(kosmos) {
+ testScope.runTest {
+ // Assert that new tile defaults to icon
+ assertThat(underTest.isIconTile(TileSpec.create("newTile"))).isTrue()
+
+ qsPreferencesRepository.setLargeTilesSpecs(setOf(TileSpec.create("newTile")))
+ runCurrent()
+
+ // Assert that the new tile was added to the large tiles set
+ assertThat(underTest.isIconTile(TileSpec.create("newTile"))).isFalse()
+ }
+ }
+
+ @Test
+ fun resize_updatesSharedPreferences() =
+ with(kosmos) {
+ testScope.runTest {
+ val latest by collectLastValue(qsPreferencesRepository.largeTilesSpecs)
+ val spec = TileSpec.create("large")
+
+ // Assert that the tile is added to the large tiles after resizing
+ underTest.resize(spec, toIcon = false)
+ assertThat(latest).contains(spec)
+
+ // Assert that the tile is removed from the large tiles after resizing
+ underTest.resize(spec, toIcon = true)
+ assertThat(latest).doesNotContain(spec)
+ }
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/domain/interactor/InfiniteGridConsistencyInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/domain/interactor/InfiniteGridConsistencyInteractorTest.kt
index 1e2e82ffeca5..ea51398e6256 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/domain/interactor/InfiniteGridConsistencyInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/domain/interactor/InfiniteGridConsistencyInteractorTest.kt
@@ -20,8 +20,8 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.kosmos.testScope
-import com.android.systemui.qs.panels.data.repository.IconTilesRepository
-import com.android.systemui.qs.panels.data.repository.iconTilesRepository
+import com.android.systemui.qs.panels.data.repository.DefaultLargeTilesRepository
+import com.android.systemui.qs.panels.data.repository.defaultLargeTilesRepository
import com.android.systemui.qs.pipeline.shared.TileSpec
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
@@ -33,21 +33,17 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class InfiniteGridConsistencyInteractorTest : SysuiTestCase() {
- private val iconOnlyTiles =
- setOf(
- TileSpec.create("smallA"),
- TileSpec.create("smallB"),
- TileSpec.create("smallC"),
- TileSpec.create("smallD"),
- TileSpec.create("smallE"),
- )
private val kosmos =
testKosmos().apply {
- iconTilesRepository =
- object : IconTilesRepository {
- override fun isIconTile(spec: TileSpec): Boolean {
- return iconOnlyTiles.contains(spec)
- }
+ defaultLargeTilesRepository =
+ object : DefaultLargeTilesRepository {
+ override val defaultLargeTiles: Set<TileSpec> =
+ setOf(
+ TileSpec.create("largeA"),
+ TileSpec.create("largeB"),
+ TileSpec.create("largeC"),
+ TileSpec.create("largeD"),
+ )
}
}
private val underTest = with(kosmos) { infiniteGridConsistencyInteractor }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/InfiniteGridLayoutTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/InfiniteGridLayoutTest.kt
index 914a09597d65..53384afb66be 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/InfiniteGridLayoutTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/InfiniteGridLayoutTest.kt
@@ -20,8 +20,8 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.kosmos.testScope
-import com.android.systemui.qs.panels.data.repository.IconTilesRepository
-import com.android.systemui.qs.panels.data.repository.iconTilesRepository
+import com.android.systemui.qs.panels.data.repository.DefaultLargeTilesRepository
+import com.android.systemui.qs.panels.data.repository.defaultLargeTilesRepository
import com.android.systemui.qs.panels.ui.viewmodel.MockTileViewModel
import com.android.systemui.qs.panels.ui.viewmodel.fixedColumnsSizeViewModel
import com.android.systemui.qs.panels.ui.viewmodel.iconTilesViewModel
@@ -37,11 +37,9 @@ import org.junit.runner.RunWith
class InfiniteGridLayoutTest : SysuiTestCase() {
private val kosmos =
testKosmos().apply {
- iconTilesRepository =
- object : IconTilesRepository {
- override fun isIconTile(spec: TileSpec): Boolean {
- return spec.spec.startsWith("small")
- }
+ defaultLargeTilesRepository =
+ object : DefaultLargeTilesRepository {
+ override val defaultLargeTiles: Set<TileSpec> = setOf(TileSpec.create("large"))
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/PartitionedGridLayoutTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/PartitionedGridLayoutTest.kt
index 3354b4d4116b..55b7454fa2c1 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/PartitionedGridLayoutTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/PartitionedGridLayoutTest.kt
@@ -20,8 +20,8 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.kosmos.testScope
-import com.android.systemui.qs.panels.data.repository.IconTilesRepository
-import com.android.systemui.qs.panels.data.repository.iconTilesRepository
+import com.android.systemui.qs.panels.data.repository.DefaultLargeTilesRepository
+import com.android.systemui.qs.panels.data.repository.defaultLargeTilesRepository
import com.android.systemui.qs.panels.ui.viewmodel.MockTileViewModel
import com.android.systemui.qs.panels.ui.viewmodel.iconTilesViewModel
import com.android.systemui.qs.panels.ui.viewmodel.partitionedGridViewModel
@@ -37,11 +37,9 @@ import org.junit.runner.RunWith
class PartitionedGridLayoutTest : SysuiTestCase() {
private val kosmos =
testKosmos().apply {
- iconTilesRepository =
- object : IconTilesRepository {
- override fun isIconTile(spec: TileSpec): Boolean {
- return spec.spec.startsWith("small")
- }
+ defaultLargeTilesRepository =
+ object : DefaultLargeTilesRepository {
+ override val defaultLargeTiles: Set<TileSpec> = setOf(TileSpec.create("large"))
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/QuickQuickSettingsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/QuickQuickSettingsViewModelTest.kt
index d36a81bcfd23..56156a8e6e61 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/QuickQuickSettingsViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/QuickQuickSettingsViewModelTest.kt
@@ -24,8 +24,8 @@ import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.testCase
import com.android.systemui.kosmos.testScope
-import com.android.systemui.qs.panels.data.repository.IconTilesRepository
-import com.android.systemui.qs.panels.data.repository.iconTilesRepository
+import com.android.systemui.qs.panels.data.repository.DefaultLargeTilesRepository
+import com.android.systemui.qs.panels.data.repository.defaultLargeTilesRepository
import com.android.systemui.qs.pipeline.domain.interactor.currentTilesInteractor
import com.android.systemui.qs.pipeline.shared.TileSpec
import com.android.systemui.res.R
@@ -40,18 +40,6 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class QuickQuickSettingsViewModelTest : SysuiTestCase() {
- private val kosmos =
- testKosmos().apply {
- iconTilesRepository =
- object : IconTilesRepository {
- override fun isIconTile(spec: TileSpec): Boolean {
- return spec.spec.startsWith(PREFIX_SMALL)
- }
- }
- }
-
- private val underTest = kosmos.quickQuickSettingsViewModel
-
private val tiles =
listOf(
"$PREFIX_SMALL:1",
@@ -66,6 +54,17 @@ class QuickQuickSettingsViewModelTest : SysuiTestCase() {
)
.map(TileSpec::create)
+ private val kosmos =
+ testKosmos().apply {
+ defaultLargeTilesRepository =
+ object : DefaultLargeTilesRepository {
+ override val defaultLargeTiles: Set<TileSpec> =
+ tiles.filter { it.spec.startsWith(PREFIX_LARGE) }.toSet()
+ }
+ }
+
+ private val underTest = kosmos.quickQuickSettingsViewModel
+
@Before
fun setUp() {
kosmos.setTiles(tiles)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/airplate/domain/interactor/AirplaneModeTileDataInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/airplane/domain/interactor/AirplaneModeTileDataInteractorTest.kt
index 89b9b7f30297..67e2fba30822 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/airplate/domain/interactor/AirplaneModeTileDataInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/airplane/domain/interactor/AirplaneModeTileDataInteractorTest.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.qs.tiles.impl.airplate.domain.interactor
+package com.android.systemui.qs.tiles.impl.airplane.domain.interactor
import android.os.UserHandle
import android.platform.test.annotations.EnabledOnRavenwood
@@ -23,7 +23,6 @@ import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectValues
import com.android.systemui.qs.tiles.base.interactor.DataUpdateTrigger
-import com.android.systemui.qs.tiles.impl.airplane.domain.interactor.AirplaneModeTileDataInteractor
import com.android.systemui.qs.tiles.impl.airplane.domain.model.AirplaneModeTileModel
import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository
import com.google.common.truth.Truth.assertThat
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/airplate/domain/interactor/AirplaneModeTileUserActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/airplane/domain/interactor/AirplaneModeTileUserActionInteractorTest.kt
index 8982d810ad8a..79fcc92a967c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/airplate/domain/interactor/AirplaneModeTileUserActionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/airplane/domain/interactor/AirplaneModeTileUserActionInteractorTest.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.qs.tiles.impl.airplate.domain.interactor
+package com.android.systemui.qs.tiles.impl.airplane.domain.interactor
import android.platform.test.annotations.EnabledOnRavenwood
import android.provider.Settings
@@ -26,7 +26,6 @@ import com.android.systemui.qs.tiles.base.actions.FakeQSTileIntentUserInputHandl
import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandlerSubject.Companion.assertThat
import com.android.systemui.qs.tiles.base.interactor.QSTileInputTestKtx.click
import com.android.systemui.qs.tiles.base.interactor.QSTileInputTestKtx.longClick
-import com.android.systemui.qs.tiles.impl.airplane.domain.interactor.AirplaneModeTileUserActionInteractor
import com.android.systemui.qs.tiles.impl.airplane.domain.model.AirplaneModeTileModel
import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository
import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor
@@ -54,7 +53,7 @@ class AirplaneModeTileUserActionInteractorTest : SysuiTestCase() {
connectivityRepository,
mobileConnectionsRepository,
),
- inputHandler
+ inputHandler,
)
@Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractorTest.kt
new file mode 100644
index 000000000000..583c10fe429e
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractorTest.kt
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles.impl.modes.domain.interactor
+
+import android.app.Flags
+import android.os.UserHandle
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
+import android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS
+import android.provider.Settings.Global.ZEN_MODE_NO_INTERRUPTIONS
+import android.provider.Settings.Global.ZEN_MODE_OFF
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.settingslib.notification.data.repository.FakeZenModeRepository
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectValues
+import com.android.systemui.qs.tiles.base.interactor.DataUpdateTrigger
+import com.android.systemui.qs.tiles.impl.modes.domain.model.ModesTileModel
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.toCollection
+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 ModesTileDataInteractorTest : SysuiTestCase() {
+ private val zenModeRepository = FakeZenModeRepository()
+
+ private val underTest = ModesTileDataInteractor(zenModeRepository)
+
+ @EnableFlags(Flags.FLAG_MODES_UI)
+ @Test
+ fun availableWhenFlagIsOn() = runTest {
+ val availability = underTest.availability(TEST_USER).toCollection(mutableListOf())
+
+ assertThat(availability).containsExactly(true)
+ }
+
+ @DisableFlags(Flags.FLAG_MODES_UI)
+ @Test
+ fun unavailableWhenFlagIsOff() = runTest {
+ val availability = underTest.availability(TEST_USER).toCollection(mutableListOf())
+
+ assertThat(availability).containsExactly(false)
+ }
+
+ @EnableFlags(Flags.FLAG_MODES_UI)
+ @Test
+ fun dataMatchesTheRepository() = runTest {
+ val dataList: List<ModesTileModel> by
+ collectValues(underTest.tileData(TEST_USER, flowOf(DataUpdateTrigger.InitialRequest)))
+ runCurrent()
+
+ // Enable zen mode
+ zenModeRepository.updateZenMode(ZEN_MODE_IMPORTANT_INTERRUPTIONS)
+ runCurrent()
+
+ // Change zen mode: it's still enabled, so this shouldn't cause another emission
+ zenModeRepository.updateZenMode(ZEN_MODE_NO_INTERRUPTIONS)
+ runCurrent()
+
+ // Disable zen mode
+ zenModeRepository.updateZenMode(ZEN_MODE_OFF)
+ runCurrent()
+
+ assertThat(dataList.map { it.isActivated }).containsExactly(false, true, false)
+ }
+
+ private companion object {
+
+ val TEST_USER = UserHandle.of(1)!!
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/reducebrightness/domain/interactor/ReduceBrightColorsTileDataInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/reducebrightness/domain/interactor/ReduceBrightColorsTileDataInteractorTest.kt
index 2e5fde8e4bd6..a5f98a739b49 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/reducebrightness/domain/interactor/ReduceBrightColorsTileDataInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/reducebrightness/domain/interactor/ReduceBrightColorsTileDataInteractorTest.kt
@@ -30,7 +30,6 @@ import com.android.systemui.qs.tiles.impl.reducebrightness.domain.model.ReduceBr
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.flowOf
-import kotlinx.coroutines.flow.toCollection
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Test
@@ -56,8 +55,7 @@ class ReduceBrightColorsTileDataInteractorTest : SysuiTestCase() {
@Test
fun alwaysAvailable() =
testScope.runTest {
- val availability = underTest.availability(TEST_USER).toCollection(mutableListOf())
-
+ val availability by collectValues(underTest.availability(TEST_USER))
assertThat(availability).hasSize(1)
assertThat(availability.last()).isEqualTo(isAvailable)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/reducebrightness/domain/interactor/ReduceBrightColorsTileUserActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/reducebrightness/domain/interactor/ReduceBrightColorsTileUserActionInteractorTest.kt
index 6ea5e63fdff6..313331286b45 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/reducebrightness/domain/interactor/ReduceBrightColorsTileUserActionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/reducebrightness/domain/interactor/ReduceBrightColorsTileUserActionInteractorTest.kt
@@ -17,9 +17,13 @@
package com.android.systemui.qs.tiles.impl.reducebrightness.domain.interactor
import android.platform.test.annotations.EnabledOnRavenwood
+import android.platform.test.annotations.RequiresFlagsDisabled
+import android.platform.test.annotations.RequiresFlagsEnabled
import android.provider.Settings
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
+import com.android.internal.R
+import com.android.server.display.feature.flags.Flags
import com.android.systemui.SysuiTestCase
import com.android.systemui.accessibility.reduceBrightColorsController
import com.android.systemui.kosmos.Kosmos
@@ -43,11 +47,22 @@ class ReduceBrightColorsTileUserActionInteractorTest : SysuiTestCase() {
private val underTest =
ReduceBrightColorsTileUserActionInteractor(
+ context.resources,
+ inputHandler,
+ controller,
+ )
+
+ private val underTestEvenDimmerEnabled =
+ ReduceBrightColorsTileUserActionInteractor(
+ context.orCreateTestableResources
+ .apply { addOverride(R.bool.config_evenDimmerEnabled, true) }
+ .resources,
inputHandler,
controller,
)
@Test
+ @RequiresFlagsDisabled(Flags.FLAG_EVEN_DIMMER)
fun handleClickWhenEnabled() = runTest {
val wasEnabled = true
controller.isReduceBrightColorsActivated = wasEnabled
@@ -58,6 +73,7 @@ class ReduceBrightColorsTileUserActionInteractorTest : SysuiTestCase() {
}
@Test
+ @RequiresFlagsDisabled(Flags.FLAG_EVEN_DIMMER)
fun handleClickWhenDisabled() = runTest {
val wasEnabled = false
controller.isReduceBrightColorsActivated = wasEnabled
@@ -68,6 +84,7 @@ class ReduceBrightColorsTileUserActionInteractorTest : SysuiTestCase() {
}
@Test
+ @RequiresFlagsDisabled(Flags.FLAG_EVEN_DIMMER)
fun handleLongClickWhenDisabled() = runTest {
val enabled = false
@@ -79,6 +96,7 @@ class ReduceBrightColorsTileUserActionInteractorTest : SysuiTestCase() {
}
@Test
+ @RequiresFlagsDisabled(Flags.FLAG_EVEN_DIMMER)
fun handleLongClickWhenEnabled() = runTest {
val enabled = true
@@ -88,4 +106,58 @@ class ReduceBrightColorsTileUserActionInteractorTest : SysuiTestCase() {
assertThat(it.intent.action).isEqualTo(Settings.ACTION_REDUCE_BRIGHT_COLORS_SETTINGS)
}
}
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_EVEN_DIMMER)
+ fun handleClickWhenEnabledEvenDimmer() = runTest {
+ val wasEnabled = true
+ controller.isReduceBrightColorsActivated = wasEnabled
+
+ underTestEvenDimmerEnabled.handleInput(
+ QSTileInputTestKtx.click(ReduceBrightColorsTileModel(wasEnabled))
+ )
+
+ assertThat(controller.isReduceBrightColorsActivated).isEqualTo(wasEnabled)
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_EVEN_DIMMER)
+ fun handleClickWhenDisabledEvenDimmer() = runTest {
+ val wasEnabled = false
+ controller.isReduceBrightColorsActivated = wasEnabled
+
+ underTestEvenDimmerEnabled.handleInput(
+ QSTileInputTestKtx.click(ReduceBrightColorsTileModel(wasEnabled))
+ )
+
+ assertThat(controller.isReduceBrightColorsActivated).isEqualTo(wasEnabled)
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_EVEN_DIMMER)
+ fun handleLongClickWhenDisabledEvenDimmer() = runTest {
+ val enabled = false
+
+ underTestEvenDimmerEnabled.handleInput(
+ QSTileInputTestKtx.longClick(ReduceBrightColorsTileModel(enabled))
+ )
+
+ QSTileIntentUserInputHandlerSubject.assertThat(inputHandler).handledOneIntentInput {
+ assertThat(it.intent.action).isEqualTo(Settings.ACTION_DISPLAY_SETTINGS)
+ }
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_EVEN_DIMMER)
+ fun handleLongClickWhenEnabledEvenDimmer() = runTest {
+ val enabled = true
+
+ underTestEvenDimmerEnabled.handleInput(
+ QSTileInputTestKtx.longClick(ReduceBrightColorsTileModel(enabled))
+ )
+
+ QSTileIntentUserInputHandlerSubject.assertThat(inputHandler).handledOneIntentInput {
+ assertThat(it.intent.action).isEqualTo(Settings.ACTION_DISPLAY_SETTINGS)
+ }
+ }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/adapter/QSSceneAdapterImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/adapter/QSSceneAdapterImplTest.kt
index b35b7bca4809..09580c5f17be 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/adapter/QSSceneAdapterImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/adapter/QSSceneAdapterImplTest.kt
@@ -38,7 +38,6 @@ import com.android.systemui.qs.dagger.QSSceneComponent
import com.android.systemui.settings.brightness.MirrorController
import com.android.systemui.shade.data.repository.fakeShadeRepository
import com.android.systemui.shade.domain.interactor.shadeInteractor
-import com.android.systemui.shade.shared.model.ShadeMode
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.capture
@@ -558,7 +557,7 @@ class QSSceneAdapterImplTest : SysuiTestCase() {
fun dispatchSplitShade() =
testScope.runTest {
val shadeRepository = kosmos.fakeShadeRepository
- shadeRepository.setShadeMode(ShadeMode.Single)
+ shadeRepository.setShadeLayoutWide(false)
val qsImpl by collectLastValue(underTest.qsImpl)
underTest.inflate(context)
@@ -566,7 +565,7 @@ class QSSceneAdapterImplTest : SysuiTestCase() {
verify(qsImpl!!).setInSplitShade(false)
- shadeRepository.setShadeMode(ShadeMode.Split)
+ shadeRepository.setShadeLayoutWide(true)
runCurrent()
verify(qsImpl!!).setInSplitShade(true)
}
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 3acb328e81af..e3a69a964b45 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
@@ -49,6 +49,7 @@ import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.toList
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
+import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -63,7 +64,8 @@ class SceneInteractorTest : SysuiTestCase() {
private val underTest = kosmos.sceneInteractor
- init {
+ @Before
+ fun setUp() {
// Init lazy Fixtures. Accessing them once makes sure that the singletons are initialized
// and therefore starts to collect StateFlows eagerly (when there are any).
kosmos.deviceUnlockedInteractor
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
index b5e47d167fa3..fd1b21332973 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
@@ -85,7 +85,6 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.TestScope
-import kotlinx.coroutines.test.advanceTimeBy
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -182,7 +181,6 @@ class SceneContainerStartableTest : SysuiTestCase() {
kosmos.headsUpNotificationRepository.activeHeadsUpRows.value =
buildNotificationRows(isPinned = false)
- advanceTimeBy(50L) // account for HeadsUpNotificationInteractor debounce
assertThat(isVisible).isFalse()
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/GoneSceneViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/GoneSceneViewModelTest.kt
index 545a0c70719f..0ab6a8250dcf 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/GoneSceneViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/GoneSceneViewModelTest.kt
@@ -28,7 +28,6 @@ import com.android.systemui.kosmos.testScope
import com.android.systemui.scene.shared.model.TransitionKeys.ToSplitShade
import com.android.systemui.shade.data.repository.shadeRepository
import com.android.systemui.shade.domain.interactor.shadeInteractor
-import com.android.systemui.shade.shared.model.ShadeMode
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -63,7 +62,7 @@ class GoneSceneViewModelTest : SysuiTestCase() {
fun downTransitionKey_splitShadeEnabled_isGoneToSplitShade() =
testScope.runTest {
val destinationScenes by collectLastValue(underTest.destinationScenes)
- shadeRepository.setShadeMode(ShadeMode.Split)
+ shadeRepository.setShadeLayoutWide(true)
runCurrent()
assertThat(destinationScenes?.get(Swipe(SwipeDirection.Down))?.transitionKey)
@@ -74,7 +73,7 @@ class GoneSceneViewModelTest : SysuiTestCase() {
fun downTransitionKey_splitShadeDisabled_isNull() =
testScope.runTest {
val destinationScenes by collectLastValue(underTest.destinationScenes)
- shadeRepository.setShadeMode(ShadeMode.Single)
+ shadeRepository.setShadeLayoutWide(false)
runCurrent()
assertThat(destinationScenes?.get(Swipe(SwipeDirection.Down))?.transitionKey).isNull()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImplTest.kt
index 78c4def5689b..3283ea154b3f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImplTest.kt
@@ -19,6 +19,8 @@ package com.android.systemui.shade.domain.interactor
import android.app.StatusBarManager.DISABLE2_NONE
import android.app.StatusBarManager.DISABLE2_NOTIFICATION_SHADE
import android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
import android.platform.test.flag.junit.FlagsParameterization
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -37,7 +39,10 @@ import com.android.systemui.kosmos.testScope
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.shade.data.repository.shadeRepository
import com.android.systemui.shade.shadeTestUtil
+import com.android.systemui.shade.shared.flag.DualShade
+import com.android.systemui.shade.shared.model.ShadeMode
import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel
import com.android.systemui.statusbar.disableflags.data.repository.fakeDisableFlagsRepository
import com.android.systemui.statusbar.phone.dozeParameters
@@ -452,4 +457,44 @@ class ShadeInteractorImplTest(flags: FlagsParameterization) : SysuiTestCase() {
val isShadeTouchable by collectLastValue(underTest.isShadeTouchable)
assertThat(isShadeTouchable).isTrue()
}
+
+ @Test
+ @DisableFlags(DualShade.FLAG_NAME)
+ fun legacyShadeMode_narrowScreen_singleShade() =
+ testScope.runTest {
+ val shadeMode by collectLastValue(underTest.shadeMode)
+ kosmos.shadeRepository.setShadeLayoutWide(false)
+
+ assertThat(shadeMode).isEqualTo(ShadeMode.Single)
+ }
+
+ @Test
+ @DisableFlags(DualShade.FLAG_NAME)
+ fun legacyShadeMode_wideScreen_splitShade() =
+ testScope.runTest {
+ val shadeMode by collectLastValue(underTest.shadeMode)
+ kosmos.shadeRepository.setShadeLayoutWide(true)
+
+ assertThat(shadeMode).isEqualTo(ShadeMode.Split)
+ }
+
+ @Test
+ @EnableFlags(DualShade.FLAG_NAME)
+ fun shadeMode_wideScreen_isDual() =
+ testScope.runTest {
+ val shadeMode by collectLastValue(underTest.shadeMode)
+ kosmos.shadeRepository.setShadeLayoutWide(true)
+
+ assertThat(shadeMode).isEqualTo(ShadeMode.Dual)
+ }
+
+ @Test
+ @EnableFlags(DualShade.FLAG_NAME)
+ fun shadeMode_narrowScreen_isDual() =
+ testScope.runTest {
+ val shadeMode by collectLastValue(underTest.shadeMode)
+ kosmos.shadeRepository.setShadeLayoutWide(false)
+
+ assertThat(shadeMode).isEqualTo(ShadeMode.Dual)
+ }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImplTest.kt
index b1bffdbb1bed..8a4319805802 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImplTest.kt
@@ -29,7 +29,6 @@ import com.android.systemui.res.R
import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.data.repository.shadeRepository
-import com.android.systemui.shade.shared.model.ShadeMode
import com.android.systemui.testKosmos
import com.google.common.truth.Truth
import com.google.common.truth.Truth.assertThat
@@ -568,21 +567,6 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() {
sceneInteractor.setTransitionState(transitionState)
// THEN interacting is false
- Truth.assertThat(interacting).isFalse()
- }
-
- @Test
- fun shadeMode() =
- testScope.runTest {
- val shadeMode by collectLastValue(underTest.shadeMode)
-
- shadeRepository.setShadeMode(ShadeMode.Split)
- assertThat(shadeMode).isEqualTo(ShadeMode.Split)
-
- shadeRepository.setShadeMode(ShadeMode.Single)
- assertThat(shadeMode).isEqualTo(ShadeMode.Single)
-
- shadeRepository.setShadeMode(ShadeMode.Split)
- assertThat(shadeMode).isEqualTo(ShadeMode.Split)
+ assertThat(interacting).isFalse()
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt
index 673d5ef5d962..da22c6d7419d 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.shade.ui.viewmodel
+import android.platform.test.annotations.DisableFlags
import android.testing.TestableLooper
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
@@ -38,7 +39,6 @@ import com.android.systemui.kosmos.testScope
import com.android.systemui.media.controls.data.repository.mediaFilterRepository
import com.android.systemui.media.controls.shared.model.MediaData
import com.android.systemui.qs.ui.adapter.fakeQSSceneAdapter
-import com.android.systemui.qs.ui.adapter.qsSceneAdapter
import com.android.systemui.res.R
import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.scene.domain.resolver.homeSceneFamilyResolver
@@ -47,6 +47,7 @@ import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.shared.model.TransitionKeys.ToSplitShade
import com.android.systemui.shade.data.repository.shadeRepository
import com.android.systemui.shade.domain.startable.shadeStartable
+import com.android.systemui.shade.shared.flag.DualShade
import com.android.systemui.shade.shared.model.ShadeMode
import com.android.systemui.testKosmos
import com.android.systemui.unfold.fakeUnfoldTransitionProgressProvider
@@ -66,6 +67,7 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper
@EnableSceneContainer
+@DisableFlags(DualShade.FLAG_NAME)
class ShadeSceneViewModelTest : SysuiTestCase() {
private val kosmos = testKosmos()
@@ -157,7 +159,7 @@ class ShadeSceneViewModelTest : SysuiTestCase() {
fun upTransitionKey_splitShadeEnabled_isGoneToSplitShade() =
testScope.runTest {
val destinationScenes by collectLastValue(underTest.destinationScenes)
- shadeRepository.setShadeMode(ShadeMode.Split)
+ shadeRepository.setShadeLayoutWide(true)
runCurrent()
assertThat(destinationScenes?.get(Swipe(SwipeDirection.Up))?.transitionKey)
@@ -168,7 +170,7 @@ class ShadeSceneViewModelTest : SysuiTestCase() {
fun upTransitionKey_splitShadeDisable_isNull() =
testScope.runTest {
val destinationScenes by collectLastValue(underTest.destinationScenes)
- shadeRepository.setShadeMode(ShadeMode.Single)
+ shadeRepository.setShadeLayoutWide(false)
runCurrent()
assertThat(destinationScenes?.get(Swipe(SwipeDirection.Up))?.transitionKey).isNull()
@@ -268,13 +270,13 @@ class ShadeSceneViewModelTest : SysuiTestCase() {
testScope.runTest {
val shadeMode by collectLastValue(underTest.shadeMode)
- shadeRepository.setShadeMode(ShadeMode.Split)
+ shadeRepository.setShadeLayoutWide(true)
assertThat(shadeMode).isEqualTo(ShadeMode.Split)
- shadeRepository.setShadeMode(ShadeMode.Single)
+ shadeRepository.setShadeLayoutWide(false)
assertThat(shadeMode).isEqualTo(ShadeMode.Single)
- shadeRepository.setShadeMode(ShadeMode.Split)
+ shadeRepository.setShadeLayoutWide(true)
assertThat(shadeMode).isEqualTo(ShadeMode.Split)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationInteractorTest.kt
index 5ef3485a8e51..8b4265f552fe 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationInteractorTest.kt
@@ -23,7 +23,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.coroutines.collectValues
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFaceAuthRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
@@ -280,64 +279,6 @@ class HeadsUpNotificationInteractorTest : SysuiTestCase() {
}
@Test
- fun isHeadsUpOrAnimatingAway_falseOnStart() =
- testScope.runTest {
- val isHeadsUpOrAnimatingAway by collectLastValue(underTest.isHeadsUpOrAnimatingAway)
-
- runCurrent()
-
- assertThat(isHeadsUpOrAnimatingAway).isFalse()
- }
-
- @Test
- fun isHeadsUpOrAnimatingAway_hasPinnedRows() =
- testScope.runTest {
- val isHeadsUpOrAnimatingAway by collectLastValue(underTest.isHeadsUpOrAnimatingAway)
-
- // WHEN a row is pinned
- headsUpRepository.setNotifications(fakeHeadsUpRowRepository("key 0", isPinned = true))
- runCurrent()
-
- assertThat(isHeadsUpOrAnimatingAway).isTrue()
- }
-
- @Test
- fun isHeadsUpOrAnimatingAway_headsUpAnimatingAway() =
- testScope.runTest {
- val isHeadsUpOrAnimatingAway by collectLastValue(underTest.isHeadsUpOrAnimatingAway)
-
- // WHEN the last row is animating away
- headsUpRepository.setHeadsUpAnimatingAway(true)
- runCurrent()
-
- assertThat(isHeadsUpOrAnimatingAway).isTrue()
- }
-
- @Test
- fun isHeadsUpOrAnimatingAway_headsUpAnimatingAwayDebounced() =
- testScope.runTest {
- val values by collectValues(underTest.isHeadsUpOrAnimatingAway)
-
- // GIVEN a row is pinned
- headsUpRepository.setNotifications(fakeHeadsUpRowRepository("key 0", isPinned = true))
- runCurrent()
- assertThat(values.size).isEqualTo(2)
- assertThat(values.first()).isFalse() // initial value
- assertThat(values.last()).isTrue()
-
- // WHEN the last row is removed
- headsUpRepository.setNotifications(emptyList())
- runCurrent()
- // AND starts to animate away
- headsUpRepository.setHeadsUpAnimatingAway(true)
- runCurrent()
-
- // THEN isHeadsUpOrAnimatingAway remained true
- assertThat(values.size).isEqualTo(2)
- assertThat(values.last()).isTrue()
- }
-
- @Test
fun showHeadsUpStatusBar_true() =
testScope.runTest {
val showHeadsUpStatusBar by collectLastValue(underTest.showHeadsUpStatusBar)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractorTest.kt
index 50b77dcf9468..1356e93db549 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractorTest.kt
@@ -22,7 +22,6 @@ import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.kosmos.testScope
import com.android.systemui.shade.data.repository.shadeRepository
-import com.android.systemui.shade.shared.model.ShadeMode
import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrimBounds
import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrimRounding
import com.android.systemui.testKosmos
@@ -66,11 +65,11 @@ class NotificationStackAppearanceInteractorTest : SysuiTestCase() {
testScope.runTest {
val stackRounding by collectLastValue(underTest.shadeScrimRounding)
- kosmos.shadeRepository.setShadeMode(ShadeMode.Single)
+ kosmos.shadeRepository.setShadeLayoutWide(false)
assertThat(stackRounding)
.isEqualTo(ShadeScrimRounding(isTopRounded = true, isBottomRounded = false))
- kosmos.shadeRepository.setShadeMode(ShadeMode.Split)
+ kosmos.shadeRepository.setShadeLayoutWide(true)
assertThat(stackRounding)
.isEqualTo(ShadeScrimRounding(isTopRounded = true, isBottomRounded = true))
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.java
deleted file mode 100644
index 3d3438eab109..000000000000
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.java
+++ /dev/null
@@ -1,243 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.policy;
-
-import static com.android.systemui.log.LogBufferHelperKt.logcatLogBuffer;
-import static com.android.systemui.util.concurrency.MockExecutorHandlerKt.mockExecutorHandler;
-
-import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertTrue;
-
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.os.Handler;
-import android.platform.test.flag.junit.FlagsParameterization;
-import android.testing.TestableLooper;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.internal.logging.UiEventLogger;
-import com.android.systemui.dump.DumpManager;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.res.R;
-import com.android.systemui.shade.domain.interactor.ShadeInteractor;
-import com.android.systemui.statusbar.NotificationShadeWindowController;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider;
-import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
-import com.android.systemui.statusbar.notification.shared.NotificationThrottleHun;
-import com.android.systemui.statusbar.phone.ConfigurationControllerImpl;
-import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
-import com.android.systemui.statusbar.phone.KeyguardBypassController;
-import com.android.systemui.util.concurrency.DelayableExecutor;
-import com.android.systemui.util.kotlin.JavaAdapter;
-import com.android.systemui.util.settings.GlobalSettings;
-import com.android.systemui.util.time.SystemClock;
-
-import kotlinx.coroutines.flow.StateFlowKt;
-
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
-
-import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
-import platform.test.runner.parameterized.Parameters;
-
-import java.util.List;
-
-@SmallTest
-@RunWith(ParameterizedAndroidJunit4.class)
-@TestableLooper.RunWithLooper
-public class HeadsUpManagerPhoneTest extends BaseHeadsUpManagerTest {
- @Rule public MockitoRule rule = MockitoJUnit.rule();
-
- private final HeadsUpManagerLogger mHeadsUpManagerLogger = new HeadsUpManagerLogger(
- logcatLogBuffer());
- @Mock private GroupMembershipManager mGroupManager;
- @Mock private VisualStabilityProvider mVSProvider;
- @Mock private StatusBarStateController mStatusBarStateController;
- @Mock private KeyguardBypassController mBypassController;
- @Mock private ConfigurationControllerImpl mConfigurationController;
- @Mock private AccessibilityManagerWrapper mAccessibilityManagerWrapper;
- @Mock private UiEventLogger mUiEventLogger;
- @Mock private JavaAdapter mJavaAdapter;
- @Mock private ShadeInteractor mShadeInteractor;
- @Mock private DumpManager dumpManager;
- private AvalancheController mAvalancheController;
-
- @Mock private Handler mBgHandler;
-
- private static final class TestableHeadsUpManagerPhone extends HeadsUpManagerPhone {
- TestableHeadsUpManagerPhone(
- Context context,
- HeadsUpManagerLogger headsUpManagerLogger,
- GroupMembershipManager groupManager,
- VisualStabilityProvider visualStabilityProvider,
- StatusBarStateController statusBarStateController,
- KeyguardBypassController keyguardBypassController,
- ConfigurationController configurationController,
- GlobalSettings globalSettings,
- SystemClock systemClock,
- DelayableExecutor executor,
- AccessibilityManagerWrapper accessibilityManagerWrapper,
- UiEventLogger uiEventLogger,
- JavaAdapter javaAdapter,
- ShadeInteractor shadeInteractor,
- AvalancheController avalancheController
- ) {
- super(
- context,
- headsUpManagerLogger,
- statusBarStateController,
- keyguardBypassController,
- groupManager,
- visualStabilityProvider,
- configurationController,
- mockExecutorHandler(executor),
- globalSettings,
- systemClock,
- executor,
- accessibilityManagerWrapper,
- uiEventLogger,
- javaAdapter,
- shadeInteractor,
- avalancheController
- );
- mMinimumDisplayTime = TEST_MINIMUM_DISPLAY_TIME;
- mAutoDismissTime = TEST_AUTO_DISMISS_TIME;
- }
- }
-
- private HeadsUpManagerPhone createHeadsUpManagerPhone() {
- return new TestableHeadsUpManagerPhone(
- mContext,
- mHeadsUpManagerLogger,
- mGroupManager,
- mVSProvider,
- mStatusBarStateController,
- mBypassController,
- mConfigurationController,
- mGlobalSettings,
- mSystemClock,
- mExecutor,
- mAccessibilityManagerWrapper,
- mUiEventLogger,
- mJavaAdapter,
- mShadeInteractor,
- mAvalancheController
- );
- }
-
- @Parameters(name = "{0}")
- public static List<FlagsParameterization> getFlags() {
- return FlagsParameterization.allCombinationsOf(NotificationThrottleHun.FLAG_NAME);
- }
-
- public HeadsUpManagerPhoneTest(FlagsParameterization flags) {
- super(flags);
- }
-
- @Before
- public void setUp() {
- when(mShadeInteractor.isAnyExpanded()).thenReturn(StateFlowKt.MutableStateFlow(false));
- final AccessibilityManagerWrapper accessibilityMgr =
- mDependency.injectMockDependency(AccessibilityManagerWrapper.class);
- when(accessibilityMgr.getRecommendedTimeoutMillis(anyInt(), anyInt()))
- .thenReturn(TEST_AUTO_DISMISS_TIME);
- when(mVSProvider.isReorderingAllowed()).thenReturn(true);
- mDependency.injectMockDependency(NotificationShadeWindowController.class);
- mContext.getOrCreateTestableResources().addOverride(
- R.integer.ambient_notification_extension_time, 500);
-
- mAvalancheController = new AvalancheController(dumpManager, mUiEventLogger, mBgHandler);
- }
-
- @Test
- public void testSnooze() {
- final HeadsUpManager hmp = createHeadsUpManagerPhone();
- final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
-
- hmp.showNotification(entry);
- hmp.snooze();
-
- assertTrue(hmp.isSnoozed(entry.getSbn().getPackageName()));
- }
-
- @Test
- public void testSwipedOutNotification() {
- final HeadsUpManager hmp = createHeadsUpManagerPhone();
- final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
-
- hmp.showNotification(entry);
- hmp.addSwipedOutNotification(entry.getKey());
-
- // Remove should succeed because the notification is swiped out
- final boolean removedImmediately = hmp.removeNotification(entry.getKey(),
- /* releaseImmediately = */ false);
-
- assertTrue(removedImmediately);
- assertFalse(hmp.isHeadsUpEntry(entry.getKey()));
- }
-
- @Test
- public void testCanRemoveImmediately_swipedOut() {
- final HeadsUpManager hmp = createHeadsUpManagerPhone();
- final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
-
- hmp.showNotification(entry);
- hmp.addSwipedOutNotification(entry.getKey());
-
- // Notification is swiped so it can be immediately removed.
- assertTrue(hmp.canRemoveImmediately(entry.getKey()));
- }
-
- @Ignore("b/141538055")
- @Test
- public void testCanRemoveImmediately_notTopEntry() {
- final HeadsUpManager hmp = createHeadsUpManagerPhone();
- final NotificationEntry earlierEntry =
- HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
- final NotificationEntry laterEntry =
- HeadsUpManagerTestUtil.createEntry(/* id = */ 1, mContext);
- laterEntry.setRow(mRow);
-
- hmp.showNotification(earlierEntry);
- hmp.showNotification(laterEntry);
-
- // Notification is "behind" a higher priority notification so we can remove it immediately.
- assertTrue(hmp.canRemoveImmediately(earlierEntry.getKey()));
- }
-
- @Test
- public void testExtendHeadsUp() {
- final HeadsUpManagerPhone hmp = createHeadsUpManagerPhone();
- final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
-
- hmp.showNotification(entry);
- hmp.extendHeadsUp();
- mSystemClock.advanceTime(TEST_AUTO_DISMISS_TIME + hmp.mExtensionTime / 2);
-
- assertTrue(hmp.isHeadsUpEntry(entry.getKey()));
- }
-}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.kt
new file mode 100644
index 000000000000..663cf1c44dad
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.kt
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.statusbar.policy
+
+import android.content.Context
+import android.os.Handler
+import android.platform.test.flag.junit.FlagsParameterization
+import android.testing.TestableLooper.RunWithLooper
+import androidx.test.filters.SmallTest
+import com.android.internal.logging.UiEventLogger
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.log.logcatLogBuffer
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.res.R
+import com.android.systemui.shade.domain.interactor.ShadeInteractor
+import com.android.systemui.statusbar.NotificationShadeWindowController
+import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider
+import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager
+import com.android.systemui.statusbar.notification.shared.NotificationThrottleHun
+import com.android.systemui.statusbar.notification.shared.NotificationsHeadsUpRefactor
+import com.android.systemui.statusbar.phone.ConfigurationControllerImpl
+import com.android.systemui.statusbar.phone.HeadsUpManagerPhone
+import com.android.systemui.statusbar.phone.KeyguardBypassController
+import com.android.systemui.util.concurrency.DelayableExecutor
+import com.android.systemui.util.concurrency.mockExecutorHandler
+import com.android.systemui.util.kotlin.JavaAdapter
+import com.android.systemui.util.settings.GlobalSettings
+import com.android.systemui.util.time.SystemClock
+import junit.framework.Assert
+import kotlinx.coroutines.flow.MutableStateFlow
+import org.junit.Before
+import org.junit.Ignore
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers
+import org.mockito.Mock
+import org.mockito.kotlin.whenever
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4
+import platform.test.runner.parameterized.Parameters
+
+@SmallTest
+@RunWith(ParameterizedAndroidJunit4::class)
+@RunWithLooper
+class HeadsUpManagerPhoneTest(flags: FlagsParameterization) : BaseHeadsUpManagerTest(flags) {
+
+ private val mHeadsUpManagerLogger = HeadsUpManagerLogger(logcatLogBuffer())
+
+ @Mock private lateinit var mGroupManager: GroupMembershipManager
+
+ @Mock private lateinit var mVSProvider: VisualStabilityProvider
+
+ @Mock private lateinit var mStatusBarStateController: StatusBarStateController
+
+ @Mock private lateinit var mBypassController: KeyguardBypassController
+
+ @Mock private lateinit var mConfigurationController: ConfigurationControllerImpl
+
+ @Mock private lateinit var mAccessibilityManagerWrapper: AccessibilityManagerWrapper
+
+ @Mock private lateinit var mUiEventLogger: UiEventLogger
+
+ @Mock private lateinit var mJavaAdapter: JavaAdapter
+
+ @Mock private lateinit var mShadeInteractor: ShadeInteractor
+
+ @Mock private lateinit var dumpManager: DumpManager
+ private lateinit var mAvalancheController: AvalancheController
+
+ @Mock private lateinit var mBgHandler: Handler
+
+ private class TestableHeadsUpManagerPhone(
+ context: Context,
+ headsUpManagerLogger: HeadsUpManagerLogger,
+ groupManager: GroupMembershipManager,
+ visualStabilityProvider: VisualStabilityProvider,
+ statusBarStateController: StatusBarStateController,
+ keyguardBypassController: KeyguardBypassController,
+ configurationController: ConfigurationController,
+ globalSettings: GlobalSettings,
+ systemClock: SystemClock,
+ executor: DelayableExecutor,
+ accessibilityManagerWrapper: AccessibilityManagerWrapper,
+ uiEventLogger: UiEventLogger,
+ javaAdapter: JavaAdapter,
+ shadeInteractor: ShadeInteractor,
+ avalancheController: AvalancheController
+ ) :
+ HeadsUpManagerPhone(
+ context,
+ headsUpManagerLogger,
+ statusBarStateController,
+ keyguardBypassController,
+ groupManager,
+ visualStabilityProvider,
+ configurationController,
+ mockExecutorHandler(executor),
+ globalSettings,
+ systemClock,
+ executor,
+ accessibilityManagerWrapper,
+ uiEventLogger,
+ javaAdapter,
+ shadeInteractor,
+ avalancheController
+ ) {
+ init {
+ mMinimumDisplayTime = TEST_MINIMUM_DISPLAY_TIME
+ mAutoDismissTime = TEST_AUTO_DISMISS_TIME
+ }
+ }
+
+ private fun createHeadsUpManagerPhone(): HeadsUpManagerPhone {
+ return TestableHeadsUpManagerPhone(
+ mContext,
+ mHeadsUpManagerLogger,
+ mGroupManager,
+ mVSProvider,
+ mStatusBarStateController,
+ mBypassController,
+ mConfigurationController,
+ mGlobalSettings,
+ mSystemClock,
+ mExecutor,
+ mAccessibilityManagerWrapper,
+ mUiEventLogger,
+ mJavaAdapter,
+ mShadeInteractor,
+ mAvalancheController
+ )
+ }
+
+ @Before
+ fun setUp() {
+ whenever(mShadeInteractor.isAnyExpanded).thenReturn(MutableStateFlow(false))
+ whenever(mVSProvider.isReorderingAllowed).thenReturn(true)
+ val accessibilityMgr =
+ mDependency.injectMockDependency(AccessibilityManagerWrapper::class.java)
+ whenever(
+ accessibilityMgr.getRecommendedTimeoutMillis(
+ ArgumentMatchers.anyInt(),
+ ArgumentMatchers.anyInt()
+ )
+ )
+ .thenReturn(TEST_AUTO_DISMISS_TIME)
+ mDependency.injectMockDependency(NotificationShadeWindowController::class.java)
+ mContext
+ .getOrCreateTestableResources()
+ .addOverride(R.integer.ambient_notification_extension_time, 500)
+ mAvalancheController = AvalancheController(dumpManager, mUiEventLogger, mBgHandler)
+ }
+
+ @Test
+ fun testSnooze() {
+ val hmp: HeadsUpManager = createHeadsUpManagerPhone()
+ val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
+ hmp.showNotification(entry)
+ hmp.snooze()
+ Assert.assertTrue(hmp.isSnoozed(entry.sbn.packageName))
+ }
+
+ @Test
+ fun testSwipedOutNotification() {
+ val hmp: HeadsUpManager = createHeadsUpManagerPhone()
+ val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
+ hmp.showNotification(entry)
+ hmp.addSwipedOutNotification(entry.key)
+
+ // Remove should succeed because the notification is swiped out
+ val removedImmediately = hmp.removeNotification(entry.key, /* releaseImmediately= */ false)
+ Assert.assertTrue(removedImmediately)
+ Assert.assertFalse(hmp.isHeadsUpEntry(entry.key))
+ }
+
+ @Test
+ fun testCanRemoveImmediately_swipedOut() {
+ val hmp: HeadsUpManager = createHeadsUpManagerPhone()
+ val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
+ hmp.showNotification(entry)
+ hmp.addSwipedOutNotification(entry.key)
+
+ // Notification is swiped so it can be immediately removed.
+ Assert.assertTrue(hmp.canRemoveImmediately(entry.key))
+ }
+
+ @Ignore("b/141538055")
+ @Test
+ fun testCanRemoveImmediately_notTopEntry() {
+ val hmp: HeadsUpManager = createHeadsUpManagerPhone()
+ val earlierEntry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
+ val laterEntry = HeadsUpManagerTestUtil.createEntry(/* id= */ 1, mContext)
+ laterEntry.row = mRow
+ hmp.showNotification(earlierEntry)
+ hmp.showNotification(laterEntry)
+
+ // Notification is "behind" a higher priority notification so we can remove it immediately.
+ Assert.assertTrue(hmp.canRemoveImmediately(earlierEntry.key))
+ }
+
+ @Test
+ fun testExtendHeadsUp() {
+ val hmp = createHeadsUpManagerPhone()
+ val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
+ hmp.showNotification(entry)
+ hmp.extendHeadsUp()
+ mSystemClock.advanceTime((TEST_AUTO_DISMISS_TIME + hmp.mExtensionTime / 2).toLong())
+ Assert.assertTrue(hmp.isHeadsUpEntry(entry.key))
+ }
+
+ companion object {
+ @get:Parameters(name = "{0}")
+ val flags: List<FlagsParameterization>
+ get() = buildList {
+ addAll(FlagsParameterization.allCombinationsOf(NotificationThrottleHun.FLAG_NAME))
+ addAll(
+ FlagsParameterization.allCombinationsOf(NotificationsHeadsUpRefactor.FLAG_NAME)
+ )
+ }
+ }
+}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialog.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialog.java
index 9e5db73cf885..cd864026207b 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialog.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialog.java
@@ -26,6 +26,7 @@ import com.android.systemui.plugins.annotations.ProvidesInterface;
@DependsOn(target = Callback.class)
public interface VolumeDialog extends Plugin {
String ACTION = "com.android.systemui.action.PLUGIN_VOLUME";
+ String ACTION_VOLUME_UNDO = "com.android.systemui.volume.ACTION_VOLUME_UNDO";
int VERSION = 1;
void init(int windowType, Callback callback);
diff --git a/packages/SystemUI/res-product/values-fr-rCA/strings.xml b/packages/SystemUI/res-product/values-fr-rCA/strings.xml
index 1b6c6099b89d..15d3606977cb 100644
--- a/packages/SystemUI/res-product/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res-product/values-fr-rCA/strings.xml
@@ -46,9 +46,9 @@
<string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"Votre téléphone fonctionne normalement maintenant.\nTouchez pour en savoir plus"</string>
<string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"Votre appareil fonctionne normalement maintenant.\nTouchez pour en savoir plus"</string>
<string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"Votre tablette fonctionne normalement maintenant.\nTouchez pour en savoir plus."</string>
- <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"Votre téléphone surchauffait et s\'est éteint afin de se refroidir. Il fonctionne normalement maintenant.\n\nIl peut surchauffer si vous :\n • utilisez. des applications qui utilisent beaucoup de ressources (jeux, vidéo, navigation, etc.)\n • téléchargez ou téléversez des fichiers lourds \n • si vous l\'utilisez lors de températures élevées."</string>
- <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"Votre téléphone surchauffait et s\'est éteint afin de se refroidir. Il fonctionne normalement maintenant.\n\nIl peut surchauffer si vous :\n • utilisez. des applications qui utilisent beaucoup de ressources (jeux, vidéo, navigation, etc.)\n • téléchargez ou téléversez des fichiers lourds \n • ou si vous l\'utilisez lors de températures élevées."</string>
- <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"Votre tablette surchauffait et s\'est éteinte afin de se refroidir. Elle fonctionne normalement maintenant.\n\nElle peut surchauffer si vous :\n • utilisez. des applications qui utilisent beaucoup de ressources (jeux, vidéo, navigation, etc.)\n • téléchargez ou téléversez des fichiers lourds \n • si vous l\'utilisez lors de températures élevées."</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"Votre téléphone surchauffait et s\'est éteint afin de se refroidir. Il fonctionne normalement maintenant.\n\nIl peut surchauffer si vous :\n • utilisez. des applis qui utilisent beaucoup de ressources (jeux, vidéo, navigation, etc.)\n • téléchargez ou téléversez des fichiers lourds \n • si vous l\'utilisez lors de températures élevées."</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"Votre téléphone surchauffait et s\'est éteint afin de se refroidir. Il fonctionne normalement maintenant.\n\nIl peut surchauffer si vous :\n • utilisez. des applis qui utilisent beaucoup de ressources (jeux, vidéo, navigation, etc.)\n • téléchargez ou téléversez des fichiers lourds \n • ou si vous l\'utilisez lors de températures élevées."</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"Votre tablette surchauffait et s\'est éteinte afin de se refroidir. Elle fonctionne normalement maintenant.\n\nElle peut surchauffer si vous :\n • utilisez. des applis qui utilisent beaucoup de ressources (jeux, vidéo, navigation, etc.)\n • téléchargez ou téléversez des fichiers lourds \n • si vous l\'utilisez lors de températures élevées."</string>
<string name="high_temp_title" product="default" msgid="5365000411304924115">"Le téléphone surchauffe"</string>
<string name="high_temp_title" product="device" msgid="6622009907401563664">"L\'appareil surchauffe"</string>
<string name="high_temp_title" product="tablet" msgid="9039733706606446616">"La tablette surchauffe"</string>
diff --git a/packages/SystemUI/res/layout/app_clips_screenshot.xml b/packages/SystemUI/res/layout/app_clips_screenshot.xml
index b09d35d46ca0..5191895549b6 100644
--- a/packages/SystemUI/res/layout/app_clips_screenshot.xml
+++ b/packages/SystemUI/res/layout/app_clips_screenshot.xml
@@ -60,6 +60,7 @@
android:layout_marginStart="16dp"
android:checked="true"
android:text="@string/backlinks_include_link"
+ android:textColor="?android:textColorSecondary"
android:visibility="gone"
app:layout_constraintBottom_toTopOf="@id/preview"
app:layout_constraintStart_toEndOf="@id/cancel"
@@ -74,6 +75,7 @@
android:drawablePadding="4dp"
android:gravity="center"
android:paddingHorizontal="8dp"
+ android:textColor="?android:textColorSecondary"
android:visibility="gone"
app:layout_constraintBottom_toTopOf="@id/preview"
app:layout_constraintStart_toEndOf="@id/backlinks_include_data"
diff --git a/packages/SystemUI/res/layout/clipboard_overlay.xml b/packages/SystemUI/res/layout/clipboard_overlay.xml
index 250076950907..65005f840598 100644
--- a/packages/SystemUI/res/layout/clipboard_overlay.xml
+++ b/packages/SystemUI/res/layout/clipboard_overlay.xml
@@ -24,18 +24,29 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@string/clipboard_overlay_window_name">
- <ImageView
+ <!-- Min edge spacing guideline off of which the preview and actions can be anchored (without
+ this we'd need to express margins as the sum of two different dimens). -->
+ <androidx.constraintlayout.widget.Guideline
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/min_edge_guideline"
+ app:layout_constraintGuide_begin="@dimen/overlay_action_container_minimum_edge_spacing"
+ android:orientation="vertical"/>
+ <!-- Negative horizontal margin because this container background must render beyond the thing
+ it's constrained by (the actions themselves). -->
+ <FrameLayout
android:id="@+id/actions_container_background"
android:visibility="gone"
android:layout_height="0dp"
android:layout_width="0dp"
android:elevation="4dp"
- android:background="@drawable/action_chip_container_background"
- android:layout_marginStart="@dimen/overlay_action_container_margin_horizontal"
+ android:background="@drawable/shelf_action_chip_container_background"
+ android:layout_marginStart="@dimen/negative_overlay_action_container_minimum_edge_spacing"
+ android:layout_marginEnd="@dimen/negative_overlay_action_container_minimum_edge_spacing"
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_constraintStart_toStartOf="@id/min_edge_guideline"
+ 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"
@@ -56,10 +67,13 @@
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/overlay_action_chip"
+ <include layout="@layout/shelf_action_chip"
android:id="@+id/share_chip"/>
- <include layout="@layout/overlay_action_chip"
+ <include layout="@layout/shelf_action_chip"
android:id="@+id/remote_copy_chip"/>
</LinearLayout>
</HorizontalScrollView>
@@ -73,7 +87,7 @@
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_constraintStart_toStartOf="@id/min_edge_guideline"
app:layout_constraintTop_toTopOf="@id/clipboard_preview"
app:layout_constraintEnd_toEndOf="@id/clipboard_preview"
app:layout_constraintBottom_toBottomOf="@id/actions_container_background"/>
diff --git a/packages/SystemUI/res/layout/clipboard_overlay2.xml b/packages/SystemUI/res/layout/clipboard_overlay2.xml
deleted file mode 100644
index 65005f840598..000000000000
--- a/packages/SystemUI/res/layout/clipboard_overlay2.xml
+++ /dev/null
@@ -1,202 +0,0 @@
-<?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">
- <!-- Min edge spacing guideline off of which the preview and actions can be anchored (without
- this we'd need to express margins as the sum of two different dimens). -->
- <androidx.constraintlayout.widget.Guideline
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:id="@+id/min_edge_guideline"
- app:layout_constraintGuide_begin="@dimen/overlay_action_container_minimum_edge_spacing"
- android:orientation="vertical"/>
- <!-- Negative horizontal margin because this container background must render beyond the thing
- it's constrained by (the actions themselves). -->
- <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/negative_overlay_action_container_minimum_edge_spacing"
- android:layout_marginEnd="@dimen/negative_overlay_action_container_minimum_edge_spacing"
- android:layout_marginBottom="@dimen/overlay_action_container_margin_bottom"
- app:layout_constraintStart_toStartOf="@id/min_edge_guideline"
- 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/min_edge_guideline"
- 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/layout/keyboard_shortcuts_search_view.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_search_view.xml
index 2cfd644e9d62..45a4af92339c 100644
--- a/packages/SystemUI/res/layout/keyboard_shortcuts_search_view.xml
+++ b/packages/SystemUI/res/layout/keyboard_shortcuts_search_view.xml
@@ -85,7 +85,7 @@
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
+ android:layout_gravity="center_vertical|start"
android:orientation="horizontal">
<Button
android:id="@+id/shortcut_system"
diff --git a/packages/SystemUI/res/layout/screenshot.xml b/packages/SystemUI/res/layout/screenshot.xml
deleted file mode 100644
index c134c8e2d339..000000000000
--- a/packages/SystemUI/res/layout/screenshot.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2011 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT 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.screenshot.ScreenshotView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/screenshot_frame"
- android:theme="@style/FloatingOverlay"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:importantForAccessibility="no">
- <ImageView
- android:id="@+id/screenshot_scrolling_scrim"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:visibility="gone"
- android:clickable="true"
- android:importantForAccessibility="no"/>
- <ImageView
- android:id="@+id/screenshot_flash"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:visibility="gone"
- android:elevation="7dp"
- android:src="@android:color/white"/>
- <include layout="@layout/screenshot_static"
- android:id="@+id/screenshot_static"/>
-</com.android.systemui.screenshot.ScreenshotView>
diff --git a/packages/SystemUI/res/layout/window_magnification_settings_view.xml b/packages/SystemUI/res/layout/window_magnification_settings_view.xml
index 12e226a47bb5..afd4fa7a5edd 100644
--- a/packages/SystemUI/res/layout/window_magnification_settings_view.xml
+++ b/packages/SystemUI/res/layout/window_magnification_settings_view.xml
@@ -33,9 +33,7 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
- android:singleLine="true"
- android:scrollHorizontally="true"
- android:ellipsize="marquee"
+ android:layout_marginEnd="@dimen/magnification_setting_view_item_horizontal_spacing"
android:text="@string/accessibility_magnifier_size"
android:textAppearance="@style/TextAppearance.MagnificationSetting.Title"
android:focusable="true"
@@ -120,9 +118,7 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
- android:singleLine="true"
- android:scrollHorizontally="true"
- android:ellipsize="marquee"
+ android:layout_marginEnd="@dimen/magnification_setting_view_item_horizontal_spacing"
android:text="@string/accessibility_allow_diagonal_scrolling"
android:textAppearance="@style/TextAppearance.MagnificationSetting.Title"
android:labelFor="@id/magnifier_horizontal_lock_switch"
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index f2945e24204d..a4b6deaac2b4 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -103,8 +103,7 @@
<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>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Voeg by nota"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"Sluit skakel in"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Skermopnemer"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Verwerk tans skermopname"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Deurlopende kennisgewing vir \'n skermopnamesessie"</string>
@@ -134,8 +133,7 @@
<string name="screenrecord_stop_dialog_message_specific_app" msgid="5285148796772616326">"Jy sal ophou om &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; op te neem"</string>
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
- <!-- no translation found for share_to_app_chip_accessibility_label (4210256229976947065) -->
- <skip />
+ <string name="share_to_app_chip_accessibility_label" msgid="4210256229976947065">"Deel tans skerm"</string>
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
@@ -143,8 +141,7 @@
<string name="share_to_app_stop_dialog_message_specific_app" msgid="124371406810544777">"Jy sal ophou om &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; te deel"</string>
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
- <!-- no translation found for cast_to_other_device_chip_accessibility_label (1680650146639059938) -->
- <skip />
+ <string name="cast_to_other_device_chip_accessibility_label" msgid="1680650146639059938">"Skerm word tans uitgesaai"</string>
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
@@ -198,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Ontsluit met gesig. Druk om voort te gaan."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Gesig is herken. Druk om voort te gaan."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Gesig is herken. Druk die ontsluitikoon om voort te gaan."</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"Ontsluit met gesig. Tik om voort te gaan."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Gestaaf"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"Kanselleer stawing"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"Meer opsies"</string>
@@ -480,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Voeg meer legstukke by"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Langdruk om legstukke te pasmaak"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Pasmaak legstukke"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"Ontsluit om legstukke te pasmaak"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"App-ikoon vir gedeaktiveerde legstuk"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Appikoon vir ’n legstuk wat geïnstalleer word"</string>
<string name="edit_widget" msgid="9030848101135393954">"Wysig legstuk"</string>
@@ -1359,15 +1354,11 @@
<string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"Word gebruik deur <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string>
<string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"Onlangs gebruik deur <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string>
<string name="shortcut_helper_category_system" msgid="462110876978937359">"Stelsel"</string>
- <!-- no translation found for shortcut_helper_category_system_controls (3153344561395751020) -->
- <skip />
- <!-- no translation found for shortcut_helper_category_system_apps (6001757545472556810) -->
- <skip />
+ <string name="shortcut_helper_category_system_controls" msgid="3153344561395751020">"Stelselkontroles"</string>
+ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Stelselapps"</string>
<string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Verrigting van veelvuldige take"</string>
- <!-- no translation found for shortcutHelper_category_recent_apps (7918731953612377145) -->
- <skip />
- <!-- no translation found for shortcutHelper_category_split_screen (1159669813444812244) -->
- <skip />
+ <string name="shortcutHelper_category_recent_apps" msgid="7918731953612377145">"Onlangse apps"</string>
+ <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Verdeelde skerm"</string>
<string name="shortcut_helper_category_input" msgid="8674018654124839566">"Invoer"</string>
<string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Appkortpaaie"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Toeganklikheid"</string>
@@ -1384,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Gaan terug"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"Swiep enige plek op die raakpaneel links of regs met drie vingers om terug te gaan."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"Raakpaneel wat drie vingers wat regs en links beweeg wys"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index cd3dc5188a25..784d1abfbb1b 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -103,8 +103,7 @@
<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>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"ወደ ማስታወሻ አክል"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"አገናኝ አካትት"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"የማያ መቅረጫ"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"የማያ ገፅ ቀረጻን በማሰናዳት ላይ"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"ለአንድ የማያ ገፅ ቀረጻ ክፍለ-ጊዜ በመካሄድ ያለ ማሳወቂያ"</string>
@@ -196,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"በመልክ ተከፍቷል። ለመቀጠል ይጫኑ።"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"መልክ ተለይቶ ታውቋል። ለመቀጠል ይጫኑ።"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"መልክ ተለይቶ ታውቋል። ለመቀጠል የመክፈቻ አዶውን ይጫኑ።"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"በመልክ ተከፍቷል። ለመቀጠል መታ ያድርጉ።"</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"የተረጋገጠ"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"ማረጋገጥን ሰርዝ"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"ተጨማሪ አማራጮች"</string>
@@ -478,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"ተጨማሪ ምግብሮችን ያክሉ"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"ምግብሮችን ለማበጀት በረጅሙ ይጫኑ"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"ምግብሮችን አብጅ"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"ምግብሮችን ለማበጀት ይክፈቱ"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"የመተግበሪያ አዶ ለተሰናከለ ምግብር"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"የምግብር የመተግበሪያ አዶ ሲጫን"</string>
<string name="edit_widget" msgid="9030848101135393954">"ምግብርን አርትዕ"</string>
@@ -1378,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"ወደኋላ ተመለስ"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"ወደኋላ ለመመለስ በመዳሰሻ ሰሌዳው ላይ በየትኛውም ቦታ ሦስት ጣቶችን በመጠቀም ወደግራ ወይም ወደቀኝ ያንሸራትቱ።"</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"ሦስት ጣቶች ወደቀኝ እና ግራ ሲንቀሳቀሱ የሚያሳይ የመዳሰሻ ሰሌዳ"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index f894a295d38c..3a8b063213ea 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -476,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"إضافة المزيد من التطبيقات المصغّرة"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"اضغط مع الاستمرار لتخصيص التطبيقات المصغّرة."</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"تخصيص التطبيقات المصغَّرة"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"يجب فتح القفل لتخصيص التطبيقات المصغّرة"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"رمز التطبيق المصغّر غير المفعّل"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"رمز تطبيق مصغَّر جارٍ تثبيته"</string>
<string name="edit_widget" msgid="9030848101135393954">"تعديل التطبيق المصغَّر"</string>
@@ -799,7 +798,7 @@
<string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"البحث في الاختصارات"</string>
<string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"لم يُعثَر على اختصارات."</string>
<string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"النظام"</string>
- <string name="keyboard_shortcut_search_category_input" msgid="5440558509904296233">"إدخال"</string>
+ <string name="keyboard_shortcut_search_category_input" msgid="5440558509904296233">"الإدخال"</string>
<string name="keyboard_shortcut_search_category_open_apps" msgid="1450959949739257562">"فتح التطبيقات"</string>
<string name="keyboard_shortcut_search_category_current_app" msgid="2011953559133734491">"التطبيق الحالي"</string>
<string name="keyboard_shortcut_a11y_show_search_results" msgid="2865241062981833705">"جارٍ عرض نتائج البحث"</string>
@@ -1376,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"رجوع"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"للرجوع، مرِّر سريعًا لليسار أو لليمين باستخدام ثلاثة أصابع في أي مكان على لوحة اللمس."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"لوحة لمس تعرض ثلاثة أصابع تتحرك يمينًا ويسارًا"</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index e8d788b6dc63..53241dd7eb0a 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -476,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"অধিক ৱিজেট যোগ দিয়ক"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"ৱিজেট কাষ্টমাইজ কৰিবলৈ দীঘলীয়াকৈ টিপক"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"ৱিজেট কাষ্টমাইজ কৰক"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"ৱিজেট কাষ্টমাইজ কৰিবলৈ আনলক কৰক"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"অক্ষম কৰা ৱিজেটৰ বাবে এপৰ চিহ্ন"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"ইনষ্টল কৰি থকা এটা ৱিজেটৰ বাবে এপৰ চিহ্ন"</string>
<string name="edit_widget" msgid="9030848101135393954">"ৱিজেট সম্পাদনা কৰক"</string>
@@ -1376,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"উভতি যাওক"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"উভতি যাবলৈ, টাচ্চপেডৰ যিকোনো স্থানত তিনিটা আঙুলি ব্যৱহাৰ কৰি বাওঁ বা সোঁফালে ছোৱাইপ কৰক।"</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"তিনিটা আঙুলি সোঁ আৰু বাওঁফালে লৰচৰ কৰা দেখুওৱা টাচ্চপেড"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 3476f11616ba..7fd21bfc1771 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -103,8 +103,7 @@
<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>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Qeydə əlavə edin"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"Keçid daxil edin"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Ekran yazıcısı"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Ekran çəkilişi emal edilir"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Ekranın video çəkimi ərzində silinməyən bildiriş"</string>
@@ -196,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Üz ilə kiliddən çıxarılıb. Davam etmək üçün basın."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Üz tanınıb. Davam etmək üçün basın."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Üz tanınıb. \"Kiliddən çıxar\" ikonasına basıb davam edin."</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"Üz ilə kiliddən çıxarılıb. Davam etmək üçün toxunun."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Doğrulandı"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"İdentifikasiyanı ləğv edin"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"Digər seçimlər"</string>
@@ -478,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Vidcetlər əlavə edin"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Basıb saxlayaraq vidcetləri fərdiləşdirin"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Vidcetləri fərdiləşdirin"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"Vidcetləri fərdiləşdirmək üçün kiliddən çıxarın"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Deaktiv edilmiş vidcet üçün tətbiq ikonası"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Quraşdırılan vidcet üçün tətbiq ikonası"</string>
<string name="edit_widget" msgid="9030848101135393954">"Vidceti redaktə edin"</string>
@@ -1378,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Geri qayıdın"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"Geri qayıtmaq üçün taçpedin istənilən yerində üç barmaqla sola və ya sağa çəkin."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"Üç barmağın sağa və sola hərəkət etdiyini göstərən taçped"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index e880a8b2d531..3b34af82507b 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -103,8 +103,7 @@
<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>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Dodaj u belešku"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"Uvrsti link"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Snimač ekrana"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Obrađujemo video snimka ekrana"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Obaveštenje o sesiji snimanja ekrana je aktivno"</string>
@@ -196,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Otključano je licem. Pritisnite da biste nastavili."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Lice je prepoznato. Pritisnite da biste nastavili."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Lice prepoznato. Pritisnite ikonu otključavanja za nastavak."</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"Otključano je licem. Dodirnite da biste nastavili."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Identitet je potvrđen"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"Otkažite potvrdu identiteta"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"Još opcija"</string>
@@ -478,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Dodajte još vidžeta"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Dugi pritisak za prilagođavanje vidžeta"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Prilagodi vidžete"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"Otključajte da biste prilagodili vidžete"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Ikona aplikacije za onemogućen vidžet"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Ikona aplikacije za vidžet koji se instalira"</string>
<string name="edit_widget" msgid="9030848101135393954">"Izmeni vidžet"</string>
@@ -1378,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Nazad"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"Da biste se vratili, prevucite ulevo ili udesno sa tri prsta bilo gde na tačpedu."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"Tačped sa prikazom tri prsta koji se pomeraju udesno i ulevo"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 995424688283..87f5bf165b0c 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -476,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Дадаць іншыя віджэты"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Доўга націскайце, каб наладзіць віджэты"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Наладзіць віджэты"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"Разблакіруйце, каб наладзіць віджэты"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Значок праграмы для адключанага віджэта"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Значок праграмы для віджэта ў працэсе ўсталявання"</string>
<string name="edit_widget" msgid="9030848101135393954">"Змяніць віджэт"</string>
@@ -1376,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Назад"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"Каб вярнуцца на папярэдні экран, правядзіце трыма пальцамі ўлева або ўправа ў любым месцы сэнсарнай панэлі."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"Паказваецца, як на сэнсарнай панэлі тры пальцы рухаюцца ўправа і ўлева"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index bb5986d02de9..1e4bf0ce0efe 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -103,8 +103,7 @@
<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>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Добавяне към бележката"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"Включване на връзката"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Запис на екрана"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Записът на екрана се обработва"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Текущо известие за сесия за записване на екрана"</string>
@@ -196,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Отключено с лице. Натиснете, за да продължите."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Лицето бе разпознато. Натиснете, за да продължите."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Лицето бе разпознато. Продължете чрез иконата за отключване."</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"Отключено с лице. Докоснете, за да продължите."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Удостоверено"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"Анулиране на удостоверяването"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"Още опции"</string>
@@ -478,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Добавете още приспособления"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Натиснете продължително за персонализ. на приспос."</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Персонализиране на приспособленията"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"Отключете, за да персонализирате приспособленията"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Икона на приложение за деактивирано приспособление"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Икона на приложение, чието приспособление се инсталира"</string>
<string name="edit_widget" msgid="9030848101135393954">"Редактиране на приспособлението"</string>
@@ -1378,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Назад"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"За да се върнете назад, прекарайте три пръста наляво или надясно по сензорния панел."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"Сензорен панел, върху който три пръста се движат надясно и наляво"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 716fee2d0107..b7439cab428f 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -103,8 +103,7 @@
<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>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"নোটে যোগ করুন"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"লিঙ্ক যোগ করুন"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"স্ক্রিন রেকর্ডার"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"স্ক্রিন রেকর্ডিং প্রসেস হচ্ছে"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"স্ক্রিন রেকর্ডিং সেশন চলার বিজ্ঞপ্তি"</string>
@@ -196,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"ফেসের সাহায্যে আনলক করা হয়েছে। চালিয়ে যেতে প্রেস করুন।"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"ফেস শনাক্ত করা হয়েছে। চালিয়ে যেতে প্রেস করুন।"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"ফেস শনাক্ত করা হয়েছে। চালিয়ে যেতে আনলক আইকন প্রেস করুন।"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"ফেসের সাহায্যে আনলক করা হয়েছে। চালিয়ে যেতে ট্যাপ করুন।"</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"প্রমাণীকৃত"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"যাচাইকরণ বাতিল করুন"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"আরও বিকল্প"</string>
@@ -478,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"আরও উইজেট যোগ করুন"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"উইজেট কাস্টমাইজ করতে বেশিক্ষণ প্রেস করুন"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"উইজেট কাস্টমাইজ করুন"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"উইজেট কাস্টমাইজ করতে আনলক করুন"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"বন্ধ করা উইজেটের জন্য অ্যাপের আইকন"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"ইনস্টল করা হচ্ছে এমন উইজেটের অ্যাপ আইকন"</string>
<string name="edit_widget" msgid="9030848101135393954">"উইজেট এডিট করুন"</string>
@@ -1378,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"ফিরে যান"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"ফিরে যেতে, টাচপ্যাডের যেকোনও জায়গায় তিনটি আঙুল দিয়ে ডান বা বাঁদিকে সোয়াইপ করুন।"</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"টাচপ্যাডে, তিনটি আঙুল ডান ও বাঁদিকে সরানো দেখানো হচ্ছে"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 5ab4faa4a970..d1878439d4ad 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -103,8 +103,7 @@
<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>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Dodaj u bilješku"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"Uključi link"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Snimač ekrana"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Obrađivanje snimka ekrana"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Obavještenje za sesiju snimanja ekrana je u toku"</string>
@@ -196,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Otključano licem. Pritisnite da nastavite."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Lice prepoznato. Pritisnite da nastavite."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Lice prepoznato. Pritisnite ikonu za otklj. da nastavite."</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"Otključano je licem. Dodirnite da nastavite."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autentificirano"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"Otkažite autentifikaciju"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"Više opcija"</string>
@@ -478,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Dodajte još vidžeta"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Pritisnite i zadržite da prilagodite vidžete"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Prilagodite vidžete"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"Otključajte da prilagodite vidžete"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Ikona aplikacije za onemogućeni vidžet"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Ikona aplikacije za vidžet koji se instalira"</string>
<string name="edit_widget" msgid="9030848101135393954">"Uredite vidžet"</string>
@@ -1378,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Nazad"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"Da se vratite, prevucite ulijevo ili udesno s tri prsta bilo gdje na dodirnoj podlozi."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"Dodirna podloga prikazuje tri prsta koji se pomjeraju desno-lijevo"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 052b1e81fcb1..13203df6f5af 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -103,8 +103,7 @@
<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>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Afegeix a una nota"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"Inclou l\'enllaç"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Gravació de pantalla"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Processant gravació de pantalla"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notificació en curs d\'una sessió de gravació de la pantalla"</string>
@@ -196,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"S\'ha desbloquejat amb la cara. Prem per continuar."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"S\'ha reconegut la cara. Prem per continuar."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"S\'ha reconegut la cara. Prem la icona per continuar."</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"S\'ha desbloquejat amb la cara. Toca per continuar."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autenticat"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"Cancel·la l\'autenticació"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"Més opcions"</string>
@@ -478,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Afegeix més widgets"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Mantén premut per personalitzar els widgets"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Personalitza els widgets"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"Desbloqueja per personalitzar els widgets"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Icona de l\'aplicació per a widget desactivat"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Icona de l\'aplicació d\'un widget que s\'està instal·lant"</string>
<string name="edit_widget" msgid="9030848101135393954">"Edita el widget"</string>
@@ -1378,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Torna"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"Per tornar enrere, llisca cap a l\'esquerra o cap a la dreta amb tres dits en qualsevol lloc del ratolí tàctil."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"Ratolí tàctil que mostra tres dits que es mouen cap a la dreta i cap a l\'esquerra"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 55af3ccad05d..3110f05c5879 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -103,8 +103,7 @@
<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>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Přidat do poznámky"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"Zahrnout odkaz"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Nahrávání obrazovky"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Záznam obrazovky se zpracovává"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Trvalé oznámení o relaci nahrávání"</string>
@@ -196,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Odemknuto obličejem. Pokračujte stisknutím."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Obličej rozpoznán. Pokračujte stisknutím."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Obličej rozpoznán. Klepněte na ikonu odemknutí."</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"Odemknuto obličejem. Pokračujte klepnutím."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Ověřeno"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"Zrušit ověření"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"Další možnosti"</string>
@@ -478,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Přidat další widgety"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Dlouhým stisknutím můžete přizpůsobit widgety"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Přizpůsobit widgety"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"Widgety lze přizpůsobit po odemknutí"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Ikona aplikace s deaktivovaným widgetem"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Ikona aplikace při probíhající instalaci widgetu"</string>
<string name="edit_widget" msgid="9030848101135393954">"Upravit widget"</string>
@@ -1378,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Zpět"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"Pokud se chcete vrátit zpět, stačí kdekoli na touchpadu přejet třemi prsty doleva nebo doprava."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"Touchpad se třemi prsty, které se pohybují doprava a doleva"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 387682787f4d..24d6d68b9aa6 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -103,8 +103,7 @@
<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>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Føj til note"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"Inkluder link"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Skærmoptagelse"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Behandler skærmoptagelse"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Konstant notifikation om skærmoptagelse"</string>
@@ -196,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Låst op ved hjælp af ansigt. Tryk for at fortsætte."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Ansigt genkendt. Tryk for at fortsætte."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Ansigt genkendt. Tryk på oplåsningsikonet for at fortsætte."</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"Låst op ved hjælp af ansigt. Tryk for at fortsætte."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Godkendt"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"Annuller godkendelsen"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"Flere valgmuligheder"</string>
@@ -478,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Tilføj flere widgets"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Hold fingeren nede for at tilpasse widgets"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Tilpas widgets"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"Lås op for at tilpasse widgets"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Appikon for deaktiveret widget"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Appikonet for en widget er ved at blive installeret"</string>
<string name="edit_widget" msgid="9030848101135393954">"Rediger widget"</string>
@@ -1378,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Gå tilbage"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"Du kan gå tilbage ved at stryge mod venstre eller højre med tre fingre et vilkårligt sted på touchpladen."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"Touchplade viser tre fingre, der bevæger sig til højre og venstre"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index b2e0ca8e078f..412c46a6e318 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -103,8 +103,7 @@
<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>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Zu Notiz hinzufügen"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"Link einschließen"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Bildschirmaufzeichnung"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Bildschirmaufzeichnung…"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Fortlaufende Benachrichtigung für eine Bildschirmaufzeichnung"</string>
@@ -196,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Gerät mit dem Gesicht entsperrt. Tippe, um fortzufahren."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Gesicht erkannt. Tippe, um fortzufahren."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Gesicht erkannt. Tippe zum Fortfahren auf das Symbol „Entsperren“."</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"Per Gesichtserkennung entsperrt. Tippe, um fortzufahren."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Authentifiziert"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"Authentifizierung abbrechen"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"Weitere Optionen"</string>
@@ -478,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Weitere Widgets hinzufügen"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Lange drücken, um Widgets anzupassen"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Widgets anpassen"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"Entsperren, um Widgets zu personalisieren"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"App-Symbol für deaktiviertes Widget"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"App-Symbol für ein Widget, das gerade installiert wird"</string>
<string name="edit_widget" msgid="9030848101135393954">"Widget bearbeiten"</string>
@@ -1378,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Zurück"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"Wenn du zurückgehen möchtest, wische an einer beliebigen Stelle des Touchpads mit drei Fingern nach links oder rechts."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"Touchpad mit drei Fingern, die sich nach links und rechts bewegen"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 766956fa3417..64b3c39bff7b 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -103,8 +103,7 @@
<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>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Προσθήκη σε σημείωση"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"Συμπερίληψη συνδέσμου"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Εγγραφή οθόνης"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Επεξεργασία εγγραφής οθόνης"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Ειδοποίηση σε εξέλιξη για μια περίοδο λειτουργίας εγγραφής οθόνης"</string>
@@ -196,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Ξεκλείδωμα με αναγνώριση προσώπου. Πατήστε για συνέχεια."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Το πρόσωπο αναγνωρίστηκε. Πατήστε για συνέχεια."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Το πρόσωπο αναγνωρ. Πατήστε το εικον. ξεκλειδ. για συνέχεια."</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"Ξεκλείδωμα με αναγνώριση προσώπου. Πατήστε για συνέχεια."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Ολοκληρώθηκε ο έλεγχος ταυτότητας"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"Ακύρωση ελέγχου ταυτότητας"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"Περισσότερες επιλογές"</string>
@@ -478,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Προσθήκη περισσότερων γραφικών στοιχείων"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Παρατεταμένο πάτημα για προσαρμογή γραφ. στοιχείων"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Προσαρμογή γραφικών στοιχείων"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"Ξεκλειδώστε για προσαρμογή των γραφικών στοιχείων"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Εικονίδιο εφαρμογής για απενεργοποιημένο γραφικό στοιχείο"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Εικονίδιο εφαρμογής για ένα γραφικό στοιχείου που εγκαθίσταται"</string>
<string name="edit_widget" msgid="9030848101135393954">"Επεξεργασία γραφικού στοιχείου"</string>
@@ -1378,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Επιστροφή"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"Για επιστροφή, σύρετε προς τα αριστερά ή προς τα δεξιά χρησιμοποιώντας τρία δάχτυλα οπουδήποτε στην επιφάνεια αφής."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"Επιφάνεια αφής στην οποία εμφανίζονται τρία δάχτυλα να κινούνται δεξιά και αριστερά"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 133c66d521ee..f1d6d51ab2f2 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -103,8 +103,7 @@
<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>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Add to note"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"Include link"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Screen recorder"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Processing screen recording"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Ongoing notification for a screen record session"</string>
@@ -196,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Unlocked by face. Press to continue."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Face recognised. Press to continue."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Face recognised. Press the unlock icon to continue."</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"Unlocked by face. Tap to continue."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Authenticated"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"Cancel authentication"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"More options"</string>
@@ -478,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Add more widgets"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Long press to customise widgets"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Customise widgets"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"Unlock to customise widgets"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"App icon for disabled widget"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"App icon for a widget being installed"</string>
<string name="edit_widget" msgid="9030848101135393954">"Edit widget"</string>
@@ -1378,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Go back"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"To go back, swipe left or right using 3 fingers anywhere on the touchpad."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"Touchpad showing 3 fingers moving right and left"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 40af8ce7401f..321f5b9bde77 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -464,8 +464,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Add more widgets"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Long press to customize widgets"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Customize widgets"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"Unlock to customize widgets"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"App icon for disabled widget"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"App icon for a widget being installed"</string>
<string name="edit_widget" msgid="9030848101135393954">"Edit widget"</string>
@@ -1357,6 +1356,8 @@
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Home gesture"</string>
<string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"Action key"</string>
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Done"</string>
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Go back"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"To go back, swipe left or right using three fingers anywhere on the touchpad."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"Touchpad showing three fingers moving right and left"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 133c66d521ee..f1d6d51ab2f2 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -103,8 +103,7 @@
<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>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Add to note"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"Include link"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Screen recorder"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Processing screen recording"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Ongoing notification for a screen record session"</string>
@@ -196,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Unlocked by face. Press to continue."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Face recognised. Press to continue."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Face recognised. Press the unlock icon to continue."</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"Unlocked by face. Tap to continue."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Authenticated"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"Cancel authentication"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"More options"</string>
@@ -478,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Add more widgets"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Long press to customise widgets"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Customise widgets"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"Unlock to customise widgets"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"App icon for disabled widget"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"App icon for a widget being installed"</string>
<string name="edit_widget" msgid="9030848101135393954">"Edit widget"</string>
@@ -1378,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Go back"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"To go back, swipe left or right using 3 fingers anywhere on the touchpad."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"Touchpad showing 3 fingers moving right and left"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 133c66d521ee..f1d6d51ab2f2 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -103,8 +103,7 @@
<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>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Add to note"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"Include link"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Screen recorder"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Processing screen recording"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Ongoing notification for a screen record session"</string>
@@ -196,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Unlocked by face. Press to continue."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Face recognised. Press to continue."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Face recognised. Press the unlock icon to continue."</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"Unlocked by face. Tap to continue."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Authenticated"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"Cancel authentication"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"More options"</string>
@@ -478,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Add more widgets"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Long press to customise widgets"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Customise widgets"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"Unlock to customise widgets"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"App icon for disabled widget"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"App icon for a widget being installed"</string>
<string name="edit_widget" msgid="9030848101135393954">"Edit widget"</string>
@@ -1378,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Go back"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"To go back, swipe left or right using 3 fingers anywhere on the touchpad."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"Touchpad showing 3 fingers moving right and left"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 52b567ae55aa..a196720cb416 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -464,8 +464,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‏‏‏‎‎‎‏‏‎‏‎‎‏‎‎‏‏‏‎‎‎‏‎‏‏‏‎‎‎‏‏‎‏‎‎‏‎‎‎‎‎‏‎‏‏‏‏‎‎‏‏‏‏‏‎‏‏‎Add more widgets‎‏‎‎‏‎"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‎‎‎‏‎‏‎‎‏‏‏‎‎‎‏‎‎‏‏‎‏‏‏‏‎‎‏‎‏‎‏‏‏‎‎‏‎‎‎‎‏‎‎‏‏‎‏‎‏‎‎‎‎‎‏‏‎Long press to customize widgets‎‏‎‎‏‎"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‎‎‎‏‎‏‏‎‎‎‏‏‏‏‏‎‏‎‎‎‎‏‏‎‏‏‎‎‎‎‏‎‎‎‏‏‏‎‎‏‎‏‏‎‏‏‏‏‏‏‏‎‎‎‏‎‏‎Customize widgets‎‏‎‎‏‎"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‎‏‏‏‏‎‎‎‎‏‎‎‎‏‎‎‏‏‎‎‎‏‏‎‎‎‎‎‏‏‏‏‎‏‏‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎Unlock to customize widgets‎‏‎‎‏‎"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‎‏‏‎‏‏‎‎‎‏‏‏‏‎‏‏‏‎‏‎‎‏‎‏‎‎‎‏‎‏‎‏‏‎‏‏‎‎‎‏‎‎‎‏‏‏‏‏‎App icon for disabled widget‎‏‎‎‏‎"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‎‎‎‏‏‏‏‏‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‏‎‏‏‏‎‏‎‏‏‎‎‏‎‏‎‎‏‎‎‎‏‏‏‎‏‏‎‏‏‎App icon for a widget being installed‎‏‎‎‏‎"</string>
<string name="edit_widget" msgid="9030848101135393954">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‏‎‎‎‎‎‎‎‏‎‎‏‎‎‎‎‎‎‎‎‎‏‎‎‎‎‎‏‎‏‎‏‏‏‏‏‎‏‎‎‏‎‎‏‎‏‎‎‎‏‎‎Edit widget‎‏‎‎‏‎"</string>
@@ -1357,6 +1356,8 @@
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‎‎‎‎‎‏‎‎‎‏‎‏‎‏‎‏‏‎‎‎‏‎‎‏‏‎‏‏‎‎‏‎‏‎‏‎‎‎‏‏‏‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‎‎Home gesture‎‏‎‎‏‎"</string>
<string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‎‎‏‎‏‏‎‎‎‎‎‎‎‎‎‎‎‎‏‎‏‏‎‏‎‏‎‎‏‏‎‏‎‏‎‏‎‎‏‎‎‎‎‏‏‏‏‎‎‏‎‎‏‎‎‎‏‏‎Action key‎‏‎‎‏‎"</string>
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‎‎‏‏‏‎‎‎‏‏‏‏‎‎‎‎‎‎‏‎‎‏‏‏‎‏‎‏‎‎‏‎‎‏‏‎‏‎‏‏‎‏‎‎‎‏‏‏‎‎‏‏‎‏‏‏‏‎Done‎‏‎‎‏‎"</string>
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‏‏‏‏‎‏‎‎‎‎‎‏‏‏‎‎‏‏‎‎‎‎‏‎‏‏‎‏‎‏‏‎‏‎‏‏‎‎‏‏‎‎‏‎‎‎‏‏‏‎‎‏‏‏‏‏‏‎Go back‎‏‎‎‏‎"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‎‏‎‎‏‏‎‎‏‎‎‎‏‎‏‏‎‎‎‏‏‏‏‏‏‏‎‏‏‏‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‎‏‏‏‎‏‏‎‏‎‎‎‎To go back, swipe left or right using three fingers anywhere on the touchpad.‎‏‎‎‏‎"</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‏‎‏‏‏‎‎‎‏‏‎‏‏‏‎‎‏‎‏‏‎‏‎‎‏‏‏‏‏‎‎‏‏‎‏‏‏‏‏‎‎‎‏‎‏‎‏‎‏‎‎‎‏‏‏‎‎Touchpad showing three fingers moving right and left‎‏‎‎‏‎"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index a5ccf57776ac..c5512534f746 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -103,8 +103,7 @@
<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>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Agregar a la nota"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"Incluir vínculo"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Grabadora de pantalla"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Procesando grabación pantalla"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notificación constante para una sesión de grabación de pantalla"</string>
@@ -134,8 +133,7 @@
<string name="screenrecord_stop_dialog_message_specific_app" msgid="5285148796772616326">"Dejarás de grabar contenido de &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;"</string>
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
- <!-- no translation found for share_to_app_chip_accessibility_label (4210256229976947065) -->
- <skip />
+ <string name="share_to_app_chip_accessibility_label" msgid="4210256229976947065">"Compartiendo pantalla"</string>
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
@@ -143,8 +141,7 @@
<string name="share_to_app_stop_dialog_message_specific_app" msgid="124371406810544777">"Dejarás de compartir contenido de &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;"</string>
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
- <!-- no translation found for cast_to_other_device_chip_accessibility_label (1680650146639059938) -->
- <skip />
+ <string name="cast_to_other_device_chip_accessibility_label" msgid="1680650146639059938">"Transmitiendo pantalla"</string>
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
@@ -198,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Desbloqueo con rostro. Presiona para continuar."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Rostro reconocido. Presiona para continuar."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Rostro reconocido. Presiona el desbloqueo para continuar."</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"Se desbloqueó con el rostro. Presiona para continuar."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autenticado"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"Cancelar autenticación"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"Más opciones"</string>
@@ -480,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Agregar más widgets"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Mantén presionado para personalizar los widgets"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Personalizar widgets"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"Desbloquea para personalizar los widgets"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Ícono de la app de widget inhabilitado"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Ícono de la app para un widget que se está instalando"</string>
<string name="edit_widget" msgid="9030848101135393954">"Modificar widget"</string>
@@ -1359,15 +1354,11 @@
<string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"En uso por <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string>
<string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"Uso reciente en <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string>
<string name="shortcut_helper_category_system" msgid="462110876978937359">"Sistema"</string>
- <!-- no translation found for shortcut_helper_category_system_controls (3153344561395751020) -->
- <skip />
- <!-- no translation found for shortcut_helper_category_system_apps (6001757545472556810) -->
- <skip />
+ <string name="shortcut_helper_category_system_controls" msgid="3153344561395751020">"Controles del sistema"</string>
+ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Apps del sistema"</string>
<string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Tareas múltiples"</string>
- <!-- no translation found for shortcutHelper_category_recent_apps (7918731953612377145) -->
- <skip />
- <!-- no translation found for shortcutHelper_category_split_screen (1159669813444812244) -->
- <skip />
+ <string name="shortcutHelper_category_recent_apps" msgid="7918731953612377145">"Apps recientes"</string>
+ <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Pantalla dividida"</string>
<string name="shortcut_helper_category_input" msgid="8674018654124839566">"Entrada"</string>
<string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Accesos directos a aplicaciones"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Accesibilidad"</string>
@@ -1384,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Atrás"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"Para volver, desliza tres dedos hacia la derecha o izquierda en cualquier lugar del panel táctil."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"Panel táctil en el que aparecen tres dedos que se mueven hacia la derecha y la izquierda"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 28601fde3705..ae0527ee8253 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -103,8 +103,7 @@
<string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> ha detectado esta captura de pantalla."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> y otras aplicaciones abiertas han detectado esta captura de pantalla."</string>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Añadir a nota"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"Incluir enlace"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Grabación de pantalla"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Procesando grabación de pantalla"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notificación continua de una sesión de grabación de la pantalla"</string>
@@ -196,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Desbloqueado con la cara. Pulsa para continuar."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Cara reconocida. Pulsa para continuar."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Cara reconocida. Pulsa el icono de desbloquear para continuar."</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"Desbloqueado con la cara. Toca para continuar."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Se ha autenticado"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"Cancelar autenticación"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"Más opciones"</string>
@@ -478,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Añade más widgets"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Mantén pulsado para personalizar los widgets"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Personalizar widgets"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"Desbloquea para personalizar los widgets"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Icono de la aplicación de widget inhabilitado"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Instalando icono de aplicación para widget"</string>
<string name="edit_widget" msgid="9030848101135393954">"Editar widget"</string>
@@ -1378,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Atrás"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"Para volver, desliza tres dedos hacia la izquierda o la derecha en cualquier punto del panel táctil."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"Panel táctil con tres dedos moviéndose hacia la derecha y la izquierda"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 60a1fbf8659c..0bc23025d15f 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -103,8 +103,7 @@
<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>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Lisa märkmesse"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"Kaasa link"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Ekraanisalvesti"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Ekraanisalvestuse töötlemine"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Pooleli märguanne ekraanikuva salvestamise seansi puhul"</string>
@@ -196,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Avati näoga. Vajutage jätkamiseks."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Nägu tuvastati. Vajutage jätkamiseks."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Nägu tuvastati. Jätkamiseks vajutage avamise ikooni."</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"Avati näoga. Puudutage jätkamiseks."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autenditud"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"Tühista autentimine"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"Rohkem valikuid"</string>
@@ -478,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Lisage rohkem vidinaid"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Vajutage pikalt vidinate kohandamiseks"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Kohanda vidinaid"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"Avage vidinate kohandamiseks"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Keelatud vidina rakenduseikoon"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Installitava vidina rakenduseikoon"</string>
<string name="edit_widget" msgid="9030848101135393954">"Muuda vidinat"</string>
@@ -1378,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Tagasi"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"Tagasiliikumiseks pühkige puuteplaadil kolme sõrmega vasakule või paremale."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"Puuteplaat kolme paremale ja vasakule liikuva sõrmega"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 2ba8a6392c4e..0307b0ec525c 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -103,8 +103,7 @@
<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>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Gehitu oharrean"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"Sartu esteka"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Pantaila-grabagailua"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Pantaila-grabaketa prozesatzen"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Pantailaren grabaketa-saioaren jakinarazpen jarraitua"</string>
@@ -196,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Aurpegiaren bidez desblokeatu da. Sakatu aurrera egiteko."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Ezagutu da aurpegia. Sakatu aurrera egiteko."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Ezagutu da aurpegia. Aurrera egiteko, sakatu desblokeatzeko ikonoa."</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"Aurpegiaren bidez desblokeatu da. Sakatu hau aurrera egiteko."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autentifikatuta"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"Utzi bertan behera autentifikazioa"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"Aukera gehiago"</string>
@@ -478,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Gehitu widget gehiago"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Widgetak pertsonalizatzeko, sakatu luze"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Pertsonalizatu widgetak"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"Desblokeatu hau widgetak pertsonalizatzeko"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Desgaitutako widgetaren aplikazio-ikonoa"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Instalatzen ari den widget bati dagokion aplikazioaren ikonoa"</string>
<string name="edit_widget" msgid="9030848101135393954">"Editatu widgeta"</string>
@@ -1378,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Egin atzera"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"Atzera egiteko, pasatu 3 hatz ezkerrera edo eskuinera ukipen-panelean."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"3 hatz ukipen-panel baten gainean eskuinera eta ezkerrera mugitzen erakusten duen irudia"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 7300d2cde90f..752cc6111368 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -103,8 +103,7 @@
<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>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"افزودن به یادداشت"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"اضافه کردن پیوند"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"ضبط‌کن صفحه‌نمایش"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"درحال پردازش ضبط صفحه‌نمایش"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"اعلان درحال انجام برای جلسه ضبط صفحه‌نمایش"</string>
@@ -196,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"قفلْ با چهره باز شد. برای ادامه، فشار دهید."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"چهره شناسایی شد. برای ادامه، فشار دهید."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"چهره شناسایی شد. برای ادامه، نماد قفل‌گشایی را فشار دهید."</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"قفل با چهره باز شد. برای ادامه ضربه بزنید."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"راستی‌آزمایی‌شده"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"لغو اصالت‌سنجی"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"گزینه‌های بیشتر"</string>
@@ -478,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"افزودن ابزارک‌های بیشتر"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"برای سفارشی‌سازی ابزارک‌ها، فشار طولانی دهید"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"سفارشی‌سازی ابزارک‌ها"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"برای سفارشی‌سازی ابزاره‌ها، قفل دستگاه را باز کنید"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"نماد برنامه برای ابزارک غیرفعال"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"نماد برنامه مربوط به ابزارکی که درحال نصب است"</string>
<string name="edit_widget" msgid="9030848101135393954">"ویرایش ابزارک"</string>
@@ -1378,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"برگشتن"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"برای برگشتن، در هر جایی از صفحه لمسی، با سه انگشت تند به‌چپ یا راست بکشید."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"صفحه لمسی که سه انگشت را درحال حرکت به‌سمت راست و چپ نشان می‌دهد"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index f01e6c0eabb1..b9eae3d2dad1 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -103,8 +103,7 @@
<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>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Lisää muistiinpanoon"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"Lisää linkki"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Näytön tallentaja"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Näytön tallennusta käsitellään"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Pysyvä ilmoitus näytön tallentamisesta"</string>
@@ -196,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Avattu kasvojen avulla. Jatka painamalla."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Kasvot tunnistettu. Jatka painamalla."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Kasvot tunnistettu. Jatka lukituksen avauskuvakkeella."</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"Avattu kasvojen avulla. Jatka napauttamalla."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Todennettu"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"Peruuta todennus"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"Lisää vaihtoehtoja"</string>
@@ -478,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Lisää widgetejä"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Yksilöi widgetit pitkällä painalluksella"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Muokkaa widgettejä"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"Avaa widgetien yksilöintiä varten"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Käytöstä poistetun widgetin sovelluskuvake"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Sovelluskuvake widgetin asentamisesta"</string>
<string name="edit_widget" msgid="9030848101135393954">"Muokkaa widgetiä"</string>
@@ -1378,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Takaisin"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"Jos haluat siirtyä takaisin, pyyhkäise kosketuslevyllä vasemmalle tai oikealle kolmella sormella."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"Kosketuslevy, jolla kolme sormea liikkuu oikealle ja vasemmalle"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA-ldrtl/strings.xml b/packages/SystemUI/res/values-fr-rCA-ldrtl/strings.xml
index 899fec0b89c6..9421af3f03ec 100644
--- a/packages/SystemUI/res/values-fr-rCA-ldrtl/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA-ldrtl/strings.xml
@@ -19,5 +19,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="recents_quick_scrub_onboarding" msgid="2452671841151577157">"Balayez l\'écran vers la gauche pour changer rapidement d\'application"</string>
+ <string name="recents_quick_scrub_onboarding" msgid="2452671841151577157">"Balayez l\'écran vers la gauche pour changer rapidement d\'appli"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index d2adbf6b3f77..b1aec7decc04 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -35,16 +35,16 @@
<string name="extreme_battery_saver_text" msgid="8455810156739865335">"Extrême"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Rotation auto de l\'écran"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"Autoriser <xliff:g id="APPLICATION">%1$s</xliff:g> à accéder à <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
- <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Autorisé <xliff:g id="APPLICATION">%1$s</xliff:g> à accéder à <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nCette application n\'a pas été autorisée à effectuer des enregistrements, mais elle pourrait enregistrer du contenu audio par l\'intermédiaire de cet appareil USB."</string>
+ <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Autorisé <xliff:g id="APPLICATION">%1$s</xliff:g> à accéder à <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nCette appli n\'a pas été autorisée à effectuer des enregistrements, mais elle pourrait enregistrer du contenu audio par l\'intermédiaire de cet appareil USB."</string>
<string name="usb_audio_device_permission_prompt_title" msgid="4221351137250093451">"Autoriser <xliff:g id="APPLICATION">%1$s</xliff:g> à accéder à <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
<string name="usb_audio_device_confirm_prompt_title" msgid="8828406516732985696">"Ouvrir <xliff:g id="APPLICATION">%1$s</xliff:g> pour utiliser <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
- <string name="usb_audio_device_prompt_warn" msgid="2504972133361130335">"Cette application n\'a pas été autorisée à effectuer des enregistrements, mais elle pourrait capturer du contenu audio par l\'intermédiaire de cet appareil USB. L\'utilisation de <xliff:g id="APPLICATION">%1$s</xliff:g> avec cet appareil peut empêcher d\'entendre les appels, les notifications et les alarmes."</string>
+ <string name="usb_audio_device_prompt_warn" msgid="2504972133361130335">"Cette appli n\'a pas été autorisée à effectuer des enregistrements, mais elle pourrait capturer du contenu audio par l\'intermédiaire de cet appareil USB. L\'utilisation de <xliff:g id="APPLICATION">%1$s</xliff:g> avec cet appareil peut empêcher d\'entendre les appels, les notifications et les alarmes."</string>
<string name="usb_audio_device_prompt" msgid="7944987408206252949">"L\'utilisation de <xliff:g id="APPLICATION">%1$s</xliff:g> avec cet appareil peut empêcher d\'entendre les appels, les notifications et les alarmes."</string>
<string name="usb_accessory_permission_prompt" msgid="717963550388312123">"Autoriser <xliff:g id="APPLICATION">%1$s</xliff:g> à accéder à <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
<string name="usb_device_confirm_prompt" msgid="4091711472439910809">"Ouvrir <xliff:g id="APPLICATION">%1$s</xliff:g> pour utiliser <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
- <string name="usb_device_confirm_prompt_warn" msgid="990208659736311769">"Ouvrir <xliff:g id="APPLICATION">%1$s</xliff:g> pour gérer <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nCette application n\'a pas été autorisée à effectuer des enregistrements, mais elle pourrait enregistrer du contenu audio par l\'intermédiaire de cet appareil USB."</string>
+ <string name="usb_device_confirm_prompt_warn" msgid="990208659736311769">"Ouvrir <xliff:g id="APPLICATION">%1$s</xliff:g> pour gérer <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nCette appli n\'a pas été autorisée à effectuer des enregistrements, mais elle pourrait enregistrer du contenu audio par l\'intermédiaire de cet appareil USB."</string>
<string name="usb_accessory_confirm_prompt" msgid="5728408382798643421">"Ouvrir <xliff:g id="APPLICATION">%1$s</xliff:g> pour utiliser <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
- <string name="usb_accessory_uri_prompt" msgid="6756649383432542382">"Aucune application installée compatible avec accessoire USB. En savoir plus sur <xliff:g id="URL">%1$s</xliff:g>"</string>
+ <string name="usb_accessory_uri_prompt" msgid="6756649383432542382">"Aucune appli installée compatible avec accessoire USB. En savoir plus sur <xliff:g id="URL">%1$s</xliff:g>"</string>
<string name="title_usb_accessory" msgid="1236358027511638648">"Accessoire USB"</string>
<string name="label_view" msgid="6815442985276363364">"Afficher"</string>
<string name="always_use_device" msgid="210535878779644679">"Toujours ouvrir <xliff:g id="APPLICATION">%1$s</xliff:g> lorsque <xliff:g id="USB_DEVICE">%2$s</xliff:g> est connecté"</string>
@@ -83,7 +83,7 @@
<string name="screenshot_failed_to_save_user_locked_text" msgid="6156607948256936920">"L\'appareil doit être déverrouillé avant qu\'une capture d\'écran puisse être enregistrée"</string>
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Essayez de faire une autre capture d\'écran"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"Impossible d\'enregistrer la capture d\'écran"</string>
- <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"L\'application ou votre organisation n\'autorise pas les saisies d\'écran"</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"L\'appli ou votre organisation n\'autorise pas les saisies d\'écran"</string>
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"La prise de captures d\'écran est bloquée par votre administrateur informatique"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Modifier"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Modifier la capture d\'écran"</string>
@@ -101,16 +101,15 @@
<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>
+ <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>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Ajouter à une note"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"Inclure le lien"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Enregistreur d\'écran"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Trait. de l\'enregist. d\'écran…"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notification en cours pour une session d\'enregistrement d\'écran"</string>
<string name="screenrecord_permission_dialog_title" msgid="303380743267672953">"Commencer l\'enregistrement?"</string>
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="4152602778470789965">"Pendant l\'enregistrement, Android a accès à tout ce qui est visible sur votre écran ou lu sur votre appareil. Par conséquent, soyez prudent avec les mots de passe, les détails du paiement, les messages, les photos et les contenus audio et vidéo."</string>
- <string name="screenrecord_permission_dialog_warning_single_app" msgid="6818309727772146138">"Lorsque vous enregistrez une application, Android a accès à tout ce qui est visible ou lu sur cette application. Par conséquent, soyez prudent avec les mots de passe, les détails du paiement, les messages, les photos et les contenus audio et vidéo."</string>
+ <string name="screenrecord_permission_dialog_warning_single_app" msgid="6818309727772146138">"Lorsque vous enregistrez une appli, Android a accès à tout ce qui est visible ou lu sur cette appli. Par conséquent, soyez prudent avec les mots de passe, les détails du paiement, les messages, les photos et les contenus audio et vidéo."</string>
<string name="screenrecord_permission_dialog_continue" msgid="5811122652514424967">"Commencer l\'enregistrement"</string>
<string name="screenrecord_audio_label" msgid="6183558856175159629">"Enregistrer des fichiers audio"</string>
<string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Audio de l\'appareil"</string>
@@ -181,7 +180,7 @@
<string name="accessibility_scanning_face" msgid="3093828357921541387">"Numérisation du visage"</string>
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"Envoyer"</string>
<string name="cancel" msgid="1089011503403416730">"Annuler"</string>
- <string name="biometric_dialog_logo" msgid="7681107853070774595">"Logo de l\'application"</string>
+ <string name="biometric_dialog_logo" msgid="7681107853070774595">"Logo de l\'appli"</string>
<string-array name="biometric_dialog_package_names_for_logo_with_overrides">
</string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"Confirmer"</string>
@@ -196,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Déverr. par reconnaissance faciale. Appuyez pour continuer."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Visage reconnu. Appuyez pour continuer."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Visage reconnu. Appuyez sur Déverrouiller pour continuer."</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"Déverrouillé avec le visage. Touchez pour continuer."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Authentifié"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"Annuler l\'authentification"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"Plus d\'options"</string>
@@ -364,7 +362,7 @@
<string name="quick_settings_cellular_detail_data_used" msgid="6798849610647988987">"Quantité de données utilisées :<xliff:g id="DATA_USED">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"Limite : <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"Avertissement : <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
- <string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Applications professionnelles"</string>
+ <string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Applis professionnelles"</string>
<string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"En pause"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Éclairage nocturne"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Activé la nuit"</string>
@@ -408,9 +406,9 @@
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Débloquer le microphone de l\'appareil?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Débloquer l\'appareil photo de l\'appareil?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Débloquer l\'appareil photo et le microphone?"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Cette action débloque l\'accès pour toutes les applications et tous les services autorisés à utiliser le microphone."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Cette action débloque l\'accès pour toutes les applications et pour tous les services autorisés à utiliser l\'appareil photo."</string>
- <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Cette action débloque l\'accès pour toutes les applications et tous les services autorisés à utiliser l\'appareil photo ou le microphone."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Cette action débloque l\'accès pour toutes les applis et tous les services autorisés à utiliser le microphone."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Cette action débloque l\'accès pour toutes les applis et pour tous les services autorisés à utiliser l\'appareil photo."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Cette action débloque l\'accès pour toutes les applis et tous les services autorisés à utiliser l\'appareil photo ou le microphone."</string>
<string name="sensor_privacy_start_use_mic_blocked_dialog_title" msgid="2640140287496469689">"Le microphone est bloqué"</string>
<string name="sensor_privacy_start_use_camera_blocked_dialog_title" msgid="7398084286822440384">"L\'appareil photo est bloqué"</string>
<string name="sensor_privacy_start_use_mic_camera_blocked_dialog_title" msgid="195236134743281973">"Le microphone et l\'appareil photo sont bloqués"</string>
@@ -422,13 +420,13 @@
<string name="sensor_privacy_mic_camera_unblocked_toast_content" msgid="7339355093282661115">"Microphone et appareil photo disponibles"</string>
<string name="sensor_privacy_mic_turned_on_dialog_title" msgid="6348853159838376513">"Microphone activé"</string>
<string name="sensor_privacy_mic_turned_off_dialog_title" msgid="5760464281790732849">"Microphone désactivé"</string>
- <string name="sensor_privacy_mic_unblocked_dialog_content" msgid="4889961886199270224">"Le microphone est activé pour toutes les applications et tous les services."</string>
- <string name="sensor_privacy_mic_blocked_no_exception_dialog_content" msgid="5864898470772965394">"L\'accès au microphone est désactivé pour toutes les applications et tous les services. Vous pouvez l\'activer dans Paramètres &gt; Confidentialité &gt; Microphone."</string>
- <string name="sensor_privacy_mic_blocked_with_exception_dialog_content" msgid="810289713700437896">"L\'accès au microphone est désactivé pour toutes les applications et tous les services. Vous pouvez modifier cette option dans Paramètres &gt; Confidentialité &gt; Microphone."</string>
+ <string name="sensor_privacy_mic_unblocked_dialog_content" msgid="4889961886199270224">"Le microphone est activé pour toutes les applis et tous les services."</string>
+ <string name="sensor_privacy_mic_blocked_no_exception_dialog_content" msgid="5864898470772965394">"L\'accès au microphone est désactivé pour toutes les applis et tous les services. Vous pouvez l\'activer dans Paramètres &gt; Confidentialité &gt; Microphone."</string>
+ <string name="sensor_privacy_mic_blocked_with_exception_dialog_content" msgid="810289713700437896">"L\'accès au microphone est désactivé pour toutes les applis et tous les services. Vous pouvez modifier cette option dans Paramètres &gt; Confidentialité &gt; Microphone."</string>
<string name="sensor_privacy_camera_turned_on_dialog_title" msgid="8039095295100075952">"Appareil photo activé"</string>
<string name="sensor_privacy_camera_turned_off_dialog_title" msgid="1936603903120742696">"Appareil photo désactivé"</string>
- <string name="sensor_privacy_camera_unblocked_dialog_content" msgid="7847190103011782278">"L\'appareil photo est activé pour toutes les applications et tous les services."</string>
- <string name="sensor_privacy_camera_blocked_dialog_content" msgid="3182428709314874616">"L\'accès à l\'appareil photo est désactivé pour toutes les applications et tous les services."</string>
+ <string name="sensor_privacy_camera_unblocked_dialog_content" msgid="7847190103011782278">"L\'appareil photo est activé pour toutes les applis et tous les services."</string>
+ <string name="sensor_privacy_camera_blocked_dialog_content" msgid="3182428709314874616">"L\'accès à l\'appareil photo est désactivé pour toutes les applis et tous les services."</string>
<string name="sensor_privacy_htt_blocked_dialog_content" msgid="3333321592997666441">"Pour utiliser le bouton du microphone, activez l\'accès au microphone dans les paramètres."</string>
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"Ouvrir les paramètres"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"Autre appareil"</string>
@@ -478,16 +476,15 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Ajouter plus de widgets"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Maintenez le doigt pour personnaliser les widgets"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Personnaliser les widgets"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
- <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Icône d\'application pour un widget désactivé"</string>
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"Déverrouiller pour personnaliser des widgets"</string>
+ <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Icône d\'appli pour un widget désactivé"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Icône d\'appli indiquant qu\'un widget est en cours d\'installation"</string>
<string name="edit_widget" msgid="9030848101135393954">"Modifier le widget"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"Retirer"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Ajouter un widget"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Terminé"</string>
<string name="label_for_button_in_empty_state_cta" msgid="7314975555382055823">"Ajouter des widgets"</string>
- <string name="title_for_empty_state_cta" msgid="6161654421223450530">"Accédez rapidement aux widgets de vos applications préférées sans déverrouiller votre tablette."</string>
+ <string name="title_for_empty_state_cta" msgid="6161654421223450530">"Accédez rapidement aux widgets de vos applis préférées sans déverrouiller votre tablette."</string>
<string name="dialog_title_to_allow_any_widget" msgid="1004820948962675644">"Autoriser n\'importe quel widget sur l\'écran de verrouillage?"</string>
<string name="button_text_to_open_settings" msgid="1987729256950941628">"Ouvrir les paramètres"</string>
<string name="work_mode_off_title" msgid="5794818421357835873">"Réactiver les applis pros?"</string>
@@ -506,45 +503,45 @@
<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>
- <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Toutes les applications et les données de cette session seront supprimées."</string>
+ <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Toutes les applis et les données de cette session seront supprimées."</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Bienvenue à nouveau dans la session Invité"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Voulez-vous poursuivre la session?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Recommencer"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Oui, continuer"</string>
<string name="guest_notification_app_name" msgid="2110425506754205509">"Mode Invité"</string>
<string name="guest_notification_session_active" msgid="5567273684713471450">"Vous êtes en mode Invité"</string>
- <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Si vous ajoutez un nouvel utilisateur, vous quitterez le mode Invité, et toutes les applications et données de la session d\'invité en cours seront supprimées."</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Si vous ajoutez un nouvel utilisateur, vous quitterez le mode Invité, et toutes les applis et données de la session d\'invité en cours seront supprimées."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Limite d\'utilisateurs atteinte"</string>
<string name="user_limit_reached_message" msgid="1070703858915935796">"{count,plural, =1{Vous ne pouvez créer qu\'un seul utilisateur.}one{Vous pouvez ajouter jusqu\'à # utilisateur.}many{Vous pouvez ajouter jusqu\'à # d\'utilisateurs.}other{Vous pouvez ajouter jusqu\'à # utilisateurs.}}"</string>
<string name="user_remove_user_title" msgid="9124124694835811874">"Supprimer l\'utilisateur?"</string>
- <string name="user_remove_user_message" msgid="6702834122128031833">"Toutes les applications et les données de cet utilisateur seront supprimées."</string>
+ <string name="user_remove_user_message" msgid="6702834122128031833">"Toutes les applis et les données de cet utilisateur seront supprimées."</string>
<string name="user_remove_user_remove" msgid="8387386066949061256">"Supprimer"</string>
<string name="media_projection_dialog_title" msgid="3316063622495360646">"Commencer à enregistrer ou à diffuser avec <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
<string name="media_projection_dialog_warning" msgid="1303664408388363598">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> aura accès à toute l\'information qui est visible sur votre écran ou lue sur votre appareil durant l\'enregistrement ou la diffusion. Cela comprend des renseignements comme les mots de passe, les détails du paiement, les photos, les messages et les contenus audio que vous faites jouer."</string>
<string name="media_projection_sys_service_dialog_title" msgid="3751133258891897878">"Commencer à enregistrer ou à diffuser?"</string>
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"Le service offrant cette fonction aura accès à toute l\'information qui est visible sur votre écran ou lu sur votre appareil pendant que vous enregistrez ou diffusez. Cela comprend des renseignements comme les mots de passe, les détails du paiement, les photos, les messages et le contenu audio que vous faites jouer."</string>
<string name="screen_share_permission_dialog_option_entire_screen" msgid="3131200488455089620">"Écran entier"</string>
- <string name="screen_share_permission_dialog_option_single_app" msgid="4350961814397220929">"Une seule application"</string>
- <string name="screen_share_permission_app_selector_title" msgid="1404878013670347899">"Partager ou enregistrer une application"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="4350961814397220929">"Une seule appli"</string>
+ <string name="screen_share_permission_app_selector_title" msgid="1404878013670347899">"Partager ou enregistrer une appli"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="9155535851866407199">"Commencer à enregistrer ou à diffuser avec <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"Lorsque vous partagez, enregistrez ou diffusez, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> a accès à tout ce qui est visible sur votre écran ou lu sur votre appareil. Par conséquent, soyez prudent avec les mots de passe, les détails du paiement, les messages, les photos et les contenus audio et vidéo."</string>
- <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"Lorsque vous partagez, enregistrez ou diffusez une application, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> a accès à tout ce qui est visible sur votre écran ou lu sur cette application. Par conséquent, soyez prudent avec les mots de passe, les détails du paiement, les messages, les photos et les contenus audio et vidéo."</string>
+ <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"Lorsque vous partagez, enregistrez ou diffusez une appli, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> a accès à tout ce qui est visible sur votre écran ou lu sur cette appli. Par conséquent, soyez prudent avec les mots de passe, les détails du paiement, les messages, les photos et les contenus audio et vidéo."</string>
<string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"Commencer"</string>
<string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> a désactivé cette option"</string>
<string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"Commencer la diffusion?"</string>
<string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"Lorsque vous diffusez, Android a accès à tout ce qui est visible sur votre écran ou lu sur votre appareil. Par conséquent, soyez prudent avec les mots de passe, les détails du paiement, les messages, les photos et les contenus audio et vidéo."</string>
- <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"Lorsque vous diffusez une application, Android a accès à tout ce qui est visible sur votre écran ou lu sur cette application. Par conséquent, soyez prudent avec les mots de passe, les détails du paiement, les messages, les photos et les contenus audio et vidéo."</string>
+ <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"Lorsque vous diffusez une appli, Android a accès à tout ce qui est visible sur votre écran ou lu sur cette appli. Par conséquent, soyez prudent avec les mots de passe, les détails du paiement, les messages, les photos et les contenus audio et vidéo."</string>
<string name="media_projection_entry_cast_permission_dialog_continue" msgid="7209890669948870042">"Commencer la diffusion"</string>
<string name="media_projection_entry_generic_permission_dialog_title" msgid="4519802931547483628">"Commencer à partager?"</string>
<string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"Lorsque vous partagez, enregistrez ou diffusez, Android a accès à tout ce qui est visible sur votre écran ou lu sur votre appareil. Par conséquent, soyez prudent avec les mots de passe, les détails du paiement, les messages, les photos et les contenus audio et vidéo."</string>
- <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"Lorsque vous partagez, enregistrez ou diffusez une application, Android a accès à tout ce qui est visible sur votre écran ou lu sur cette application. Par conséquent, soyez prudent avec les mots de passe, les détails du paiement, les messages, les photos et les contenus audio et vidéo."</string>
+ <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"Lorsque vous partagez, enregistrez ou diffusez une appli, Android a accès à tout ce qui est visible sur votre écran ou lu sur cette appli. Par conséquent, soyez prudent avec les mots de passe, les détails du paiement, les messages, les photos et les contenus audio et vidéo."</string>
<string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"Commencer"</string>
- <string name="media_projection_task_switcher_text" msgid="590885489897412359">"Le partage s\'interrompt lorsque vous changez d\'application"</string>
- <string name="media_projection_task_switcher_action_switch" msgid="8682258717291921123">"Partager plutôt cette application"</string>
+ <string name="media_projection_task_switcher_text" msgid="590885489897412359">"Le partage s\'interrompt lorsque vous changez d\'appli"</string>
+ <string name="media_projection_task_switcher_action_switch" msgid="8682258717291921123">"Partager plutôt cette appli"</string>
<string name="media_projection_task_switcher_action_back" msgid="5324164224147845282">"Revenir en arrière"</string>
- <string name="media_projection_task_switcher_notification_channel" msgid="7613206306777814253">"Commutateur d\'application"</string>
+ <string name="media_projection_task_switcher_notification_channel" msgid="7613206306777814253">"Commutateur d\'appli"</string>
<string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"Bloquée par votre administrateur informatique"</string>
- <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"La fonctionnalité de capture d\'écran est désactivée par l\'application Device Policy"</string>
+ <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"La fonctionnalité de capture d\'écran est désactivée par l\'appli Device Policy"</string>
<string name="clear_all_notifications_text" msgid="348312370303046130">"Tout effacer"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Gérer"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Historique"</string>
@@ -576,8 +573,8 @@
<string name="quick_settings_disclosure_managed_profile_network_activity" msgid="2636594621387832827">"Votre administrateur informatique a accès à l\'activité sur le réseau de votre profil professionnel"</string>
<string name="quick_settings_disclosure_monitoring" msgid="8548019955631378680">"Le réseau peut être surveillé"</string>
<string name="quick_settings_disclosure_vpns" msgid="3586175303518266301">"Cet appareil est connecté à Internet par l\'intermédiaire de RPV"</string>
- <string name="quick_settings_disclosure_managed_profile_named_vpn" msgid="153393105176944100">"Vos applications professionnelles sont connectées à Internet par l\'intermédiaire de <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
- <string name="quick_settings_disclosure_personal_profile_named_vpn" msgid="451254750289172191">"Vos applications personnelles sont connectées à Internet par l\'intermédiaire de <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
+ <string name="quick_settings_disclosure_managed_profile_named_vpn" msgid="153393105176944100">"Vos applis professionnelles sont connectées à Internet par l\'intermédiaire de <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
+ <string name="quick_settings_disclosure_personal_profile_named_vpn" msgid="451254750289172191">"Vos applis personnelles sont connectées à Internet par l\'intermédiaire de <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="quick_settings_disclosure_named_vpn" msgid="6191822916936028208">"Cet appareil est connecté à Internet par l\'intermédiaire de <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="monitoring_title_financed_device" msgid="3659962357973919387">"Cet appareil est fourni par <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
<string name="monitoring_title_device_owned" msgid="7029691083837606324">"Gestion d\'appareils"</string>
@@ -586,9 +583,9 @@
<string name="monitoring_subtitle_ca_certificate" msgid="8588092029755175800">"Certificats CA"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"Afficher les politiques"</string>
<string name="monitoring_button_view_controls" msgid="8316440345340701117">"Afficher les commandes"</string>
- <string name="monitoring_description_named_management" msgid="505833016545056036">"Votre appareil appartient à <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>.\n\nVotre administrateur informatique peut contrôler et gérer les paramètres, l\'accès aux données d\'entreprise, les applications, les données associées à l\'appareil et les renseignements sur sa position.\n\nPour obtenir plus d\'information, communiquez avec votre administrateur informatique."</string>
- <string name="monitoring_financed_description_named_management" msgid="6108439201399938668">"<xliff:g id="ORGANIZATION_NAME_0">%1$s</xliff:g> pourrait être en mesure d\'accéder aux données associées à cet appareil, de modifier ses paramètres et de gérer des applications.\n\nSi vous avez des questions, communiquez avec <xliff:g id="ORGANIZATION_NAME_1">%2$s</xliff:g>."</string>
- <string name="monitoring_description_management" msgid="4308879039175729014">"Cet appareil appartient à votre organisation.\n\nVotre administrateur informatique peut contrôler et gérer les paramètres, l\'accès aux données d\'entreprise, les applications, les données associées à votre appareil et les renseignements sur sa position.\n\nPour obtenir plus d\'information, communiquez avec votre administrateur informatique."</string>
+ <string name="monitoring_description_named_management" msgid="505833016545056036">"Votre appareil appartient à <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>.\n\nVotre administrateur informatique peut contrôler et gérer les paramètres, l\'accès aux données d\'entreprise, les applis, les données associées à l\'appareil et les renseignements sur sa position.\n\nPour obtenir plus d\'information, communiquez avec votre administrateur informatique."</string>
+ <string name="monitoring_financed_description_named_management" msgid="6108439201399938668">"<xliff:g id="ORGANIZATION_NAME_0">%1$s</xliff:g> pourrait être en mesure d\'accéder aux données associées à cet appareil, de modifier ses paramètres et de gérer des applis.\n\nSi vous avez des questions, communiquez avec <xliff:g id="ORGANIZATION_NAME_1">%2$s</xliff:g>."</string>
+ <string name="monitoring_description_management" msgid="4308879039175729014">"Cet appareil appartient à votre organisation.\n\nVotre administrateur informatique peut contrôler et gérer les paramètres, l\'accès aux données d\'entreprise, les applis, les données associées à votre appareil et les renseignements sur sa position.\n\nPour obtenir plus d\'information, communiquez avec votre administrateur informatique."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Votre entreprise a installé une autorité de certification sur cet appareil. Votre trafic sur le réseau sécurisé peut être contrôlé ou modifié."</string>
<string name="monitoring_description_managed_profile_ca_certificate" msgid="7904323416598435647">"Votre entreprise a installé une autorité de certification dans votre profil professionnel. Votre trafic sur le réseau sécurisé peut être contrôlé ou modifié."</string>
<string name="monitoring_description_ca_certificate" msgid="448923057059097497">"Une autorité de certification est installée sur cet appareil. Votre trafic sur le réseau sécurisé peut être contrôlé ou modifié."</string>
@@ -597,11 +594,11 @@
<string name="monitoring_description_named_vpn" msgid="8220190039787149671">"Cet appareil est connecté à Internet par l\'intermédiaire de <xliff:g id="VPN_APP">%1$s</xliff:g>. Votre activité réseau, y compris les courriels et les données de navigation, est visible par le fournisseur de RPV."</string>
<string name="monitoring_description_managed_device_named_vpn" msgid="7693648349547785255">"Cet appareil est connecté à Internet par l\'intermédiaire de <xliff:g id="VPN_APP">%1$s</xliff:g>. Votre activité réseau, y compris les courriels et les données de navigation, est visible par votre administrateur informatique."</string>
<string name="monitoring_description_two_named_vpns" msgid="6726394451199620634">"Cet appareil est connecté à Internet par l\'intermédiaire de <xliff:g id="VPN_APP_0">%1$s</xliff:g> et de <xliff:g id="VPN_APP_1">%2$s</xliff:g>. Votre activité réseau, y compris les courriels et les données de navigation, est visible par votre administrateur informatique."</string>
- <string name="monitoring_description_managed_profile_named_vpn" msgid="7254359257263069766">"Vos applications professionnelles sont connectées à Internet par l\'intermédiaire de <xliff:g id="VPN_APP">%1$s</xliff:g>. Votre activité réseau dans les applications professionnelles, y compris les courriels et les données de navigation, est visible par votre administrateur informatique et par votre fournisseur de RPV."</string>
- <string name="monitoring_description_personal_profile_named_vpn" msgid="5083909710727365452">"Vos applications personnelles sont connectées à Internet par l\'intermédiaire de <xliff:g id="VPN_APP">%1$s</xliff:g>. Votre activité réseau, y compris les courriels et les données de navigation, est visible par votre fournisseur de RPV."</string>
+ <string name="monitoring_description_managed_profile_named_vpn" msgid="7254359257263069766">"Vos applis professionnelles sont connectées à Internet par l\'intermédiaire de <xliff:g id="VPN_APP">%1$s</xliff:g>. Votre activité réseau dans les applis professionnelles, y compris les courriels et les données de navigation, est visible par votre administrateur informatique et par votre fournisseur de RPV."</string>
+ <string name="monitoring_description_personal_profile_named_vpn" msgid="5083909710727365452">"Vos applis personnelles sont connectées à Internet par l\'intermédiaire de <xliff:g id="VPN_APP">%1$s</xliff:g>. Votre activité réseau, y compris les courriels et les données de navigation, est visible par votre fournisseur de RPV."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="8292589617720435430">" "</string>
<string name="monitoring_description_vpn_settings" msgid="5264167033247632071">"Ouvrir les paramètres RPV"</string>
- <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Cet appareil est géré par ton parent. Ton parent peut voir et gérer de l\'information, comme les applications que tu utilises, ta position et ton temps d\'utilisation des écrans."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Cet appareil est géré par ton parent. Ton parent peut voir et gérer de l\'information, comme les applis que tu utilises, ta position et ton temps d\'utilisation des écrans."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"RPV"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Maintenu déverrouillé par TrustAgent"</string>
<string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"L\'appareil a été verrouillé : trop de tentatives d\'authentification"</string>
@@ -621,21 +618,21 @@
<string name="csd_500_system_lowered_text" product="default" msgid="7414943302186884124">"Le niveau du volume des écouteurs a dépassé la limite de sécurité pour cette semaine"</string>
<string name="csd_button_keep_listening" product="default" msgid="4093794049149286784">"Poursuivre l\'écoute"</string>
<string name="csd_button_lower_volume" product="default" msgid="5347210412376264579">"Diminuer le volume"</string>
- <string name="screen_pinning_title" msgid="9058007390337841305">"L\'application est épinglée"</string>
+ <string name="screen_pinning_title" msgid="9058007390337841305">"L\'appli est épinglée"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Cet écran est épinglé jusqu\'à ce que vous annuliez l\'opération. Pour annuler l\'épinglage, maintenez le doigt sur « Retour » et « Aperçu »."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Cet écran est épinglé jusqu\'à ce que vous annuliez l\'opération. Pour annuler l\'épinglage, maintenez le doigt sur les touches Retour et Accueil."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Cet écran est épinglé jusqu\'à ce que vous annuliez l\'épinglage. Pour annuler l\'épinglage, balayez l\'écran vers le haut et gardez le doigt dessus."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Cet écran est épinglé jusqu\'à ce que vous annuliez l\'opération. Pour annuler l\'épinglage, maintenez le doigt sur « Aperçu »."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Cet écran est épinglé jusqu\'à ce que vous annuliez l\'opération. Pour annuler l\'épinglage, maintenez le doigt sur la touche Accueil."</string>
<string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Certaines données personnelles pourraient être accessibles (comme les contacts et le contenu des courriels)."</string>
- <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"L\'application épinglée peut ouvrir d\'autres applications."</string>
- <string name="screen_pinning_toast" msgid="8177286912533744328">"Pour annuler l\'épinglage de cette application, maintenez un doigt sur les touches Retour et Aperçu"</string>
- <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Pour annuler l\'épinglage de cette application, maintenez un doigt sur les touches Retour et Accueil"</string>
- <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Pour annuler l\'épinglage de cette application, balayez-la vers le haut et maintenez-la"</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"L\'appli épinglée peut ouvrir d\'autres applis."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"Pour annuler l\'épinglage de cette appli, maintenez un doigt sur les touches Retour et Aperçu"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Pour annuler l\'épinglage de cette appli, maintenez un doigt sur les touches Retour et Accueil"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Pour annuler l\'épinglage de cette appli, balayez-la vers le haut et maintenez-la"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"OK"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"Non, merci"</string>
- <string name="screen_pinning_start" msgid="7483998671383371313">"Application épinglée"</string>
- <string name="screen_pinning_exit" msgid="4553787518387346893">"L\'épinglage de l\'application a été annulé"</string>
+ <string name="screen_pinning_start" msgid="7483998671383371313">"Appli épinglée"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"L\'épinglage de l\'appli a été annulé"</string>
<string name="stream_voice_call" msgid="7468348170702375660">"Appeler"</string>
<string name="stream_system" msgid="7663148785370565134">"Système"</string>
<string name="stream_ring" msgid="7550670036738697526">"Sonnerie"</string>
@@ -807,34 +804,34 @@
<string name="keyboard_shortcut_a11y_show_search_results" msgid="2865241062981833705">"Affichage des résultats de recherche en cours…"</string>
<string name="keyboard_shortcut_a11y_filter_system" msgid="7744143131119370483">"Affichage des raccourcis du système en cours…"</string>
<string name="keyboard_shortcut_a11y_filter_input" msgid="4589316004510335529">"Affichage des raccourcis d\'entrée en cours…"</string>
- <string name="keyboard_shortcut_a11y_filter_open_apps" msgid="6175417687221004059">"Affichage des raccourcis qui ouvrent les applications en cours…"</string>
- <string name="keyboard_shortcut_a11y_filter_current_app" msgid="7944592357493737911">"Affichage des raccourcis de l\'application actuelle en cours…"</string>
+ <string name="keyboard_shortcut_a11y_filter_open_apps" msgid="6175417687221004059">"Affichage des raccourcis qui ouvrent les applis en cours…"</string>
+ <string name="keyboard_shortcut_a11y_filter_current_app" msgid="7944592357493737911">"Affichage des raccourcis de l\'appli actuelle en cours…"</string>
<string name="group_system_access_notification_shade" msgid="1619028907006553677">"Afficher les notifications"</string>
<string name="group_system_full_screenshot" msgid="5742204844232667785">"Prendre une capture d\'écran"</string>
<string name="group_system_access_system_app_shortcuts" msgid="8562482996626694026">"Afficher les raccourcis"</string>
<string name="group_system_go_back" msgid="2730322046244918816">"Retour"</string>
<string name="group_system_access_home_screen" msgid="4130366993484706483">"Aller à l’écran d’accueil"</string>
- <string name="group_system_overview_open_apps" msgid="5659958952937994104">"Afficher les applications récentes"</string>
- <string name="group_system_cycle_forward" msgid="5478663965957647805">"Parcourir les applications récentes"</string>
- <string name="group_system_cycle_back" msgid="8194102916946802902">"Parcourir les applications récentes en sens inverse"</string>
- <string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Ouvrir la liste des applications"</string>
+ <string name="group_system_overview_open_apps" msgid="5659958952937994104">"Afficher les applis récentes"</string>
+ <string name="group_system_cycle_forward" msgid="5478663965957647805">"Parcourir les applis récentes"</string>
+ <string name="group_system_cycle_back" msgid="8194102916946802902">"Parcourir les applis récentes en sens inverse"</string>
+ <string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Ouvrir la liste des applis"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"Ouvrir les paramètres"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Ouvrir l\'Assistant"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"Écran de verrouillage"</string>
<string name="group_system_quick_memo" msgid="3764560265935722903">"Prendre une note"</string>
<string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Multitâche"</string>
- <string name="system_multitasking_rhs" msgid="8714224917276297810">"Utiliser l\'Écran divisé avec l\'application actuelle à droite"</string>
- <string name="system_multitasking_lhs" msgid="8402954791206308783">"Utiliser l\'Écran divisé avec l\'application actuelle à gauche"</string>
+ <string name="system_multitasking_rhs" msgid="8714224917276297810">"Utiliser l\'Écran divisé avec l\'appli actuelle à droite"</string>
+ <string name="system_multitasking_lhs" msgid="8402954791206308783">"Utiliser l\'Écran divisé avec l\'appli actuelle à gauche"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"Passer de l\'écran divisé au plein écran"</string>
- <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Passer à l\'application à droite ou en dessous avec l\'Écran divisé"</string>
- <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Passer à l\'application à gauche ou au-dessus avec l\'Écran divisé"</string>
- <string name="system_multitasking_replace" msgid="7410071959803642125">"En mode d\'écran divisé : remplacer une application par une autre"</string>
+ <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Passer à l\'appli à droite ou en dessous avec l\'Écran divisé"</string>
+ <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Passer à l\'appli à gauche ou au-dessus avec l\'Écran divisé"</string>
+ <string name="system_multitasking_replace" msgid="7410071959803642125">"En mode d\'écran divisé : remplacer une appli par une autre"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Entrée"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Passer à la langue suivante"</string>
<string name="input_switch_input_language_previous" msgid="6043341362202336623">"Passer à la langue précédente"</string>
<string name="input_access_emoji" msgid="8105642858900406351">"Accéder aux émojis"</string>
<string name="input_access_voice_typing" msgid="7291201476395326141">"Accéder à l\'entrée vocale"</string>
- <string name="keyboard_shortcut_group_applications" msgid="7386239431100651266">"Applications"</string>
+ <string name="keyboard_shortcut_group_applications" msgid="7386239431100651266">"Applis"</string>
<string name="keyboard_shortcut_group_applications_assist" msgid="6772492350416591448">"Assistant"</string>
<string name="keyboard_shortcut_group_applications_browser" msgid="2776211137869809251">"Navigateur"</string>
<string name="keyboard_shortcut_group_applications_contacts" msgid="2807268086386201060">"Contacts"</string>
@@ -934,27 +931,27 @@
<string name="lockscreen_unlock_left" msgid="1417801334370269374">"Le raccourci gauche déverrouille aussi :"</string>
<string name="lockscreen_unlock_right" msgid="4658008735541075346">"Le raccourci droit déverrouille aussi :"</string>
<string name="lockscreen_none" msgid="4710862479308909198">"Aucun"</string>
- <string name="tuner_launch_app" msgid="3906265365971743305">"Lancer l\'application <xliff:g id="APP">%1$s</xliff:g>"</string>
- <string name="tuner_other_apps" msgid="7767462881742291204">"Autres applications"</string>
+ <string name="tuner_launch_app" msgid="3906265365971743305">"Lancer l\'appli <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="tuner_other_apps" msgid="7767462881742291204">"Autres applis"</string>
<string name="tuner_circle" msgid="5270591778160525693">"Cercle"</string>
<string name="tuner_plus" msgid="4130366441154416484">"Plus"</string>
<string name="tuner_minus" msgid="5258518368944598545">"Moins"</string>
<string name="tuner_left" msgid="5758862558405684490">"Gauche"</string>
<string name="tuner_right" msgid="8247571132790812149">"Droite"</string>
<string name="tuner_menu" msgid="363690665924769420">"Menu"</string>
- <string name="tuner_app" msgid="6949280415826686972">"Application <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="tuner_app" msgid="6949280415826686972">"Appli <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="notification_channel_alerts" msgid="3385787053375150046">"Alertes"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Pile"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Saisies d\'écran"</string>
- <string name="notification_channel_instant" msgid="7556135423486752680">"Applications instantanées"</string>
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Applis instantanées"</string>
<string name="notification_channel_setup" msgid="7660580986090760350">"Configuration"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Stockage"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Conseils"</string>
<string name="notification_channel_accessibility" msgid="8956203986976245820">"Accessibilité"</string>
- <string name="instant_apps" msgid="8337185853050247304">"Applications instantanées"</string>
+ <string name="instant_apps" msgid="8337185853050247304">"Applis instantanées"</string>
<string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> en cours d\'exécution"</string>
- <string name="instant_apps_message" msgid="6112428971833011754">"Application ouverte sans avoir été installée."</string>
- <string name="instant_apps_message_with_help" msgid="1816952263531203932">"Application ouverte sans avoir été installée. Touchez ici pour en savoir plus."</string>
+ <string name="instant_apps_message" msgid="6112428971833011754">"Appli ouverte sans avoir été installée."</string>
+ <string name="instant_apps_message_with_help" msgid="1816952263531203932">"Appli ouverte sans avoir été installée. Touchez ici pour en savoir plus."</string>
<string name="app_info" msgid="5153758994129963243">"Détails de l\'appli"</string>
<string name="go_to_web" msgid="636673528981366511">"Ouvrir le navigateur"</string>
<string name="mobile_data" msgid="4564407557775397216">"Données cellulaires"</string>
@@ -965,9 +962,9 @@
<string name="dnd_is_off" msgid="3185706903793094463">"Le mode Ne pas déranger est désactivé"</string>
<string name="dnd_is_on" msgid="7009368176361546279">"Mode Ne pas déranger activé"</string>
<string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"Le mode Ne pas déranger a été activé par une règle automatique (<xliff:g id="ID_1">%s</xliff:g>)."</string>
- <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"Le mode Ne pas déranger a été activé par une application (<xliff:g id="ID_1">%s</xliff:g>)."</string>
- <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"Le mode Ne pas déranger a été activé par une règle automatique ou une application."</string>
- <string name="running_foreground_services_title" msgid="5137313173431186685">"Applications qui fonctionnent en arrière-plan"</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"Le mode Ne pas déranger a été activé par une appli (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"Le mode Ne pas déranger a été activé par une règle automatique ou une appli."</string>
+ <string name="running_foreground_services_title" msgid="5137313173431186685">"Applis qui fonctionnent en arrière-plan"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Touchez pour afficher des détails sur l\'utilisation de la pile et des données"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Désactiver les données cellulaires?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"Vous n\'aurez pas accès aux données ni à Internet avec <xliff:g id="CARRIER">%s</xliff:g>. Vous ne pourrez accéder à Internet que par Wi-Fi."</string>
@@ -976,18 +973,18 @@
<string name="auto_data_switch_disable_message" msgid="5885533647399535852">"Il n\'y aura pas de basculement automatique entre les données mobiles selon la disponibilité"</string>
<string name="auto_data_switch_dialog_negative_button" msgid="2370876875999891444">"Non merci"</string>
<string name="auto_data_switch_dialog_positive_button" msgid="8531782041263087564">"Oui, basculer"</string>
- <string name="touch_filtered_warning" msgid="8119511393338714836">"Une application obscurcit une demande d\'autorisation, alors Paramètres ne peut pas vérifier votre réponse."</string>
+ <string name="touch_filtered_warning" msgid="8119511393338714836">"Une appli obscurcit une demande d\'autorisation, alors Paramètres ne peut pas vérifier votre réponse."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"Autoriser <xliff:g id="APP_0">%1$s</xliff:g> à afficher <xliff:g id="APP_2">%2$s</xliff:g> tranches?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- Il peut lire de l\'information de <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="slice_permission_text_2" msgid="6758906940360746983">"- Il peut effectuer des actions dans <xliff:g id="APP">%1$s</xliff:g>"</string>
- <string name="slice_permission_checkbox" msgid="4242888137592298523">"Autoriser <xliff:g id="APP">%1$s</xliff:g> à afficher des tranches de n\'importe quelle application"</string>
+ <string name="slice_permission_checkbox" msgid="4242888137592298523">"Autoriser <xliff:g id="APP">%1$s</xliff:g> à afficher des tranches de n\'importe quelle appli"</string>
<string name="slice_permission_allow" msgid="6340449521277951123">"Autoriser"</string>
<string name="slice_permission_deny" msgid="6870256451658176895">"Refuser"</string>
<string name="auto_saver_title" msgid="6873691178754086596">"Toucher pour activer la fonction Économiseur de pile"</string>
<string name="auto_saver_text" msgid="3214960308353838764">"Activer si la pile est susceptible de s\'épuiser totalement"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"Non merci"</string>
<string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"En cours d\'utilisation"</string>
- <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Des applications utilisent votre <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Des applis utilisent votre <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" et "</string>
<string name="ongoing_privacy_dialog_using_op" msgid="426635338010011796">"En cours d\'utilisation par : <xliff:g id="APPLICATION_NAME">%1$s</xliff:g>"</string>
@@ -1060,7 +1057,7 @@
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"basculer"</string>
<string name="accessibility_floating_button_action_edit" msgid="1688227814600463987">"Modifier"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Commandes des appareils"</string>
- <string name="controls_providers_title" msgid="6879775889857085056">"Sélectionnez l\'application pour laquelle ajouter des commandes"</string>
+ <string name="controls_providers_title" msgid="6879775889857085056">"Sélectionnez l\'appli pour laquelle ajouter des commandes"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# commande ajoutée.}one{# commande ajoutée.}many{# de commandes ajoutées.}other{# commandes ajoutées.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Supprimé"</string>
<string name="controls_panel_authorization_title" msgid="267429338785864842">"Ajouter <xliff:g id="APPNAME">%s</xliff:g>?"</string>
@@ -1077,11 +1074,11 @@
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Faites glisser les commandes pour les réorganiser"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Toutes les commandes ont été retirées"</string>
<string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Modifications non enregistrées"</string>
- <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"Afficher autres applications"</string>
+ <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"Afficher autres applis"</string>
<string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"Réorganiser"</string>
<string name="controls_favorite_add_controls" msgid="1221420435546694004">"Ajouter des commandes"</string>
<string name="controls_favorite_back_to_editing" msgid="184125114090062713">"Retour à la modification"</string>
- <string name="controls_favorite_load_error" msgid="5126216176144877419">"Impossible de charger les commandes. Vérifiez l\'application <xliff:g id="APP">%s</xliff:g> pour vous assurer que les paramètres de l\'application n\'ont pas changé."</string>
+ <string name="controls_favorite_load_error" msgid="5126216176144877419">"Impossible de charger les commandes. Vérifiez l\'appli <xliff:g id="APP">%s</xliff:g> pour vous assurer que les paramètres de l\'appli n\'ont pas changé."</string>
<string name="controls_favorite_load_none" msgid="7687593026725357775">"Les commandes compatibles ne sont pas accessibles"</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Autre"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Ajouter aux commandes des appareils"</string>
@@ -1090,9 +1087,9 @@
<string name="controls_dialog_message" msgid="342066938390663844">"Suggestion de <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_tile_locked" msgid="731547768182831938">"Appareil verrouillé"</string>
<string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Afficher et contrôler les appareils à partir de l\'écran de verrouillage?"</string>
- <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Vous pouvez ajouter des commandes pour vos appareils externes à l\'écran de verrouillage.\n\nL\'application de votre appareil peut vous permettre de contrôler certains appareils sans déverrouiller votre téléphone ou votre tablette.\n\nVous pouvez apporter des modifications à tout moment dans les paramètres."</string>
+ <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Vous pouvez ajouter des commandes pour vos appareils externes à l\'écran de verrouillage.\n\nL\'appli de votre appareil peut vous permettre de contrôler certains appareils sans déverrouiller votre téléphone ou votre tablette.\n\nVous pouvez apporter des modifications à tout moment dans les paramètres."</string>
<string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Contrôler les appareils à partir de l\'écran de verrouillage?"</string>
- <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"Vous pouvez contrôler certains appareils sans déverrouiller votre téléphone ou votre tablette. L\'application de votre appareil détermine quels appareils peuvent être contrôlés de cette manière."</string>
+ <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"Vous pouvez contrôler certains appareils sans déverrouiller votre téléphone ou votre tablette. L\'appli de votre appareil détermine quels appareils peuvent être contrôlés de cette manière."</string>
<string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"Non merci"</string>
<string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Oui"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Le NIP contient des lettres ou des symboles"</string>
@@ -1135,14 +1132,14 @@
<string name="controls_error_timeout" msgid="794197289772728958">"Délai expiré, vérifiez l\'appli"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Introuvable"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"La commande n\'est pas accessible"</string>
- <string name="controls_error_removed_message" msgid="2885911717034750542">"Impossible d\'accéder à <xliff:g id="DEVICE">%1$s</xliff:g>. Vérifiez l\'application <xliff:g id="APPLICATION">%2$s</xliff:g> pour vous assurer que la commande est toujours offerte et que les paramètres de l\'application n\'ont pas changé."</string>
- <string name="controls_open_app" msgid="483650971094300141">"Ouvrir l\'application"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"Impossible d\'accéder à <xliff:g id="DEVICE">%1$s</xliff:g>. Vérifiez l\'appli <xliff:g id="APPLICATION">%2$s</xliff:g> pour vous assurer que la commande est toujours offerte et que les paramètres de l\'appli n\'ont pas changé."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"Ouvrir l\'appli"</string>
<string name="controls_error_generic" msgid="352500456918362905">"Impossible de charger l\'état"</string>
<string name="controls_error_failed" msgid="960228639198558525">"Erreur. Veuillez réessayer."</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Ajouter des commandes"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Modifier des commandes"</string>
- <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Ajouter une application"</string>
- <string name="controls_menu_remove" msgid="3006525275966023468">"Retirer l\'application"</string>
+ <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Ajouter une appli"</string>
+ <string name="controls_menu_remove" msgid="3006525275966023468">"Retirer l\'appli"</string>
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Ajouter des sorties"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"Groupe"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Un appareil sélectionné"</string>
@@ -1150,8 +1147,8 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(déconnecté)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Changement impossible. Touchez pour réessayer."</string>
<string name="media_output_dialog_pairing_new" msgid="5098212763195577270">"Connecter un appareil"</string>
- <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Pour diffuser cette session, veuillez ouvrir l\'application."</string>
- <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Application inconnue"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Pour diffuser cette session, veuillez ouvrir l\'appli."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Appli inconnue"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Arrêter la diffusion"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Appareils disponibles pour la sortie audio."</string>
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Volume"</string>
@@ -1239,13 +1236,13 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Connexion automatique au Wi-Fi impossible pour le moment"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Tout afficher"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Pour changer de réseau, débranchez le câble Ethernet"</string>
- <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Pour améliorer l\'expérience de l\'appareil, les applications et les services peuvent quand même rechercher des réseaux Wi-Fi en tout temps, même lorsque le Wi-Fi est désactivé. Vous pouvez modifier vos préférences dans les paramètres de recherche de réseaux Wi-Fi. "<annotation id="link">"Modifier"</annotation></string>
+ <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Pour améliorer l\'expérience de l\'appareil, les applis et les services peuvent quand même rechercher des réseaux Wi-Fi en tout temps, même lorsque le Wi-Fi est désactivé. Vous pouvez modifier vos préférences dans les paramètres de recherche de réseaux Wi-Fi. "<annotation id="link">"Modifier"</annotation></string>
<string name="turn_off_airplane_mode" msgid="8425587763226548579">"Désactiver le mode Avion"</string>
- <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"L\'application <xliff:g id="APPNAME">%1$s</xliff:g> veut ajouter la tuile suivante au menu Paramètres rapides"</string>
+ <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"L\'appli <xliff:g id="APPNAME">%1$s</xliff:g> veut ajouter la tuile suivante au menu Paramètres rapides"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Ajouter la tuile"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Ne pas ajouter de tuile"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Choisir l\'utilisateur"</string>
- <string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{# application est active}one{# application est active}many{# d\'applications sont actives}other{# applications sont actives}}"</string>
+ <string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{# appli est active}one{# appli est active}many{# d\'applis sont actives}other{# applis sont actives}}"</string>
<string name="fgs_dot_content_description" msgid="2865071539464777240">"Nouvelle information"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Applis actives"</string>
<string name="fgs_manager_dialog_message" msgid="2670045017200730076">"Ces applis sont actives et s\'exécutent même lorsque vous ne les utilisez pas. Cela améliore leur fonctionnalité, mais peut également affecter l\'autonomie de la pile."</string>
@@ -1291,16 +1288,16 @@
<string name="log_access_confirmation_title" msgid="4843557604739943395">"Autoriser <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> à accéder à l\'ensemble des journaux de l\'appareil?"</string>
<string name="log_access_confirmation_allow" msgid="752147861593202968">"Autoriser un accès unique"</string>
<string name="log_access_confirmation_deny" msgid="2389461495803585795">"Ne pas autoriser"</string>
- <string name="log_access_confirmation_body" msgid="6883031912003112634">"Les journaux de l\'appareil enregistrent ce qui se passe sur celui-ci. Les applications peuvent utiliser ces journaux pour trouver et résoudre des problèmes.\n\nCertains journaux peuvent contenir des renseignements confidentiels. N\'autorisez donc que les applications auxquelles vous faites confiance puisque celles-ci pourront accéder à l\'ensemble des journaux de l\'appareil. \n\nMême si vous n\'autorisez pas cette application à accéder à l\'ensemble des journaux de l\'appareil, elle aura toujours accès à ses propres journaux. Le fabricant de votre appareil pourrait toujours être en mesure d\'accéder à certains journaux ou renseignements sur votre appareil."</string>
+ <string name="log_access_confirmation_body" msgid="6883031912003112634">"Les journaux de l\'appareil enregistrent ce qui se passe sur celui-ci. Les applis peuvent utiliser ces journaux pour trouver et résoudre des problèmes.\n\nCertains journaux peuvent contenir des renseignements confidentiels. N\'autorisez donc que les applis auxquelles vous faites confiance puisque celles-ci pourront accéder à l\'ensemble des journaux de l\'appareil. \n\nMême si vous n\'autorisez pas cette appli à accéder à l\'ensemble des journaux de l\'appareil, elle aura toujours accès à ses propres journaux. Le fabricant de votre appareil pourrait toujours être en mesure d\'accéder à certains journaux ou renseignements sur votre appareil."</string>
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"En savoir plus"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"En savoir plus : <xliff:g id="URL">%s</xliff:g>"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Ouvrir <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Pour ajouter l\'application portefeuille sous forme de raccourci, assurez-vous que l\'application est installée"</string>
- <string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Pour ajouter l\'application Portefeuille sous forme de raccourci, assurez-vous qu\'au moins une carte a été ajoutée"</string>
- <string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Pour ajouter l\'application Home sous forme de raccourci, assurez-vous que l\'application est installée"</string>
+ <string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Pour ajouter l\'appli portefeuille sous forme de raccourci, assurez-vous que l\'appli est installée"</string>
+ <string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Pour ajouter l\'appli Portefeuille sous forme de raccourci, assurez-vous qu\'au moins une carte a été ajoutée"</string>
+ <string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Pour ajouter l\'appli Home sous forme de raccourci, assurez-vous que l\'appli est installée"</string>
<string name="home_quick_affordance_unavailable_configure_the_app" msgid="604424593994493281">"• Au moins un appareil ou un panneau d\'appareils est accessible"</string>
- <string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Sélectionnez une application de prise de notes par défaut pour utiliser le raccourci de prise de notes"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"Sélectionner l\'application"</string>
+ <string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Sélectionnez une appli de prise de notes par défaut pour utiliser le raccourci de prise de notes"</string>
+ <string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"Sélectionner l\'appli"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Maintenir le doigt sur raccourci"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Annuler"</string>
<string name="rear_display_bottom_sheet_confirm" msgid="1507591562761552899">"Changer d\'écran maintenant"</string>
@@ -1317,10 +1314,10 @@
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Connectez votre stylet à un chargeur"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Pile du stylet faible"</string>
<string name="video_camera" msgid="7654002575156149298">"Caméra"</string>
- <string name="call_from_work_profile_title" msgid="5418253516453177114">"Impossible d\'appeler à partir d\'une application personnelle"</string>
- <string name="call_from_work_profile_text" msgid="2856337395968118274">"Votre organisation vous autorise à passer des appels uniquement à partir d\'applications professionnelles"</string>
+ <string name="call_from_work_profile_title" msgid="5418253516453177114">"Impossible d\'appeler à partir d\'une appli personnelle"</string>
+ <string name="call_from_work_profile_text" msgid="2856337395968118274">"Votre organisation vous autorise à passer des appels uniquement à partir d\'applis professionnelles"</string>
<string name="call_from_work_profile_action" msgid="2937701298133010724">"Passer au profil professionnel"</string>
- <string name="install_dialer_on_work_profile_action" msgid="2014659711597862506">"Installer une application de téléphone professionnelle"</string>
+ <string name="install_dialer_on_work_profile_action" msgid="2014659711597862506">"Installer une appli de téléphone professionnelle"</string>
<string name="call_from_work_profile_close" msgid="5830072964434474143">"Annuler"</string>
<string name="lock_screen_settings" msgid="6152703934761402399">"Personn. l\'écran de verrouillage"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Déverrouiller pour personnaliser l\'écran de verrouillage"</string>
@@ -1330,8 +1327,8 @@
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Microphone bloqué"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"Ne pas déranger"</string>
<string name="assistant_attention_content_description" msgid="4166330881435263596">"La présence d\'un utilisateur est détectée"</string>
- <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Définir l\'application de prise de notes par défaut dans les Paramètres"</string>
- <string name="install_app" msgid="5066668100199613936">"Installer l\'application"</string>
+ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Définir l\'appli de prise de notes par défaut dans les Paramètres"</string>
+ <string name="install_app" msgid="5066668100199613936">"Installer l\'appli"</string>
<string name="dismissible_keyguard_swipe" msgid="8377597870094949432">"Balayer vers le haut pour continuer"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Dupliquer l\'écran sur un moniteur externe?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Votre écran intérieur sera dupliqué. Votre écran frontal sera désactivé."</string>
@@ -1339,12 +1336,12 @@
<string name="dismiss_dialog" msgid="2195508495854675882">"Fermer"</string>
<string name="connected_display_icon_desc" msgid="6373560639989971997">"Écran connecté"</string>
<string name="privacy_dialog_title" msgid="7839968133469098311">"Microphone et appareil photo"</string>
- <string name="privacy_dialog_summary" msgid="2458769652125995409">"Utilisation récente par les applications"</string>
+ <string name="privacy_dialog_summary" msgid="2458769652125995409">"Utilisation récente par les applis"</string>
<string name="privacy_dialog_more_button" msgid="7610604080293562345">"Afficher l\'accès récent"</string>
<string name="privacy_dialog_done_button" msgid="4504330708531434263">"OK"</string>
<string name="privacy_dialog_expand_action" msgid="9129262348628331377">"Développer et afficher les options"</string>
<string name="privacy_dialog_collapse_action" msgid="277419962019466347">"Réduire"</string>
- <string name="privacy_dialog_close_app_button" msgid="8006250171305878606">"Fermer cette application"</string>
+ <string name="privacy_dialog_close_app_button" msgid="8006250171305878606">"Fermer cette appli"</string>
<string name="privacy_dialog_close_app_message" msgid="1316408652526310985">"<xliff:g id="APP_NAME">%1$s</xliff:g> fermé"</string>
<string name="privacy_dialog_manage_service" msgid="8320590856621823604">"Gérer le service"</string>
<string name="privacy_dialog_manage_permissions" msgid="2543451567190470413">"Gérer l\'accès"</string>
@@ -1378,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Retour"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"Pour revenir en arrière, balayez vers la gauche ou la droite en utilisant trois doigts n\'importe où sur le pavé tactile."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"Pavé tactile montrant trois doigts se déplaçant à droite et à gauche"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 45e5c020327b..8618b38c3c8d 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -103,8 +103,7 @@
<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>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Ajouter à la note"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"Inclure le lien"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Enregistreur d\'écran"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Enregistrement de l\'écran…"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notification en cours pour une session d\'enregistrement de l\'écran"</string>
@@ -196,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Déverrouillé par visage. Appuyez pour continuer."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Visage reconnu. Appuyez pour continuer."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Visage reconnu. Appuyez sur l\'icône de déverrouillage pour continuer."</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"Déverrouillé par le visage. Appuyez pour continuer."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Authentifié"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"Annuler l\'authentification"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"Plus d\'options"</string>
@@ -478,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Ajouter des widgets"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Appuyez de manière prolongée pour personnaliser les widgets"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Personnaliser les widgets"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"Déverrouiller pour personnaliser les widgets"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Icône d\'appli du widget désactivé"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Icône d\'application indiquant qu\'un widget est en cours d\'installation"</string>
<string name="edit_widget" msgid="9030848101135393954">"Modifier le widget"</string>
@@ -1378,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Retour"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"Pour retourner en arrière, balayez vers la gauche avec trois doigts n\'importe où sur le pavé tactile."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"Pavé tactile sur lequel trois doigts glissent vers la droite, puis vers la gauche"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 99e9b7823536..b44dc45da2dd 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -103,8 +103,7 @@
<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>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Engadir a unha nota"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"Incluír ligazón"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Gravadora da pantalla"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Procesando gravación pantalla"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notificación de actividade en curso sobre unha sesión de gravación de pantalla"</string>
@@ -196,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Usouse o desbloqueo facial. Preme para continuar."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Recoñeceuse a cara. Preme para continuar."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Recoñeceuse a cara. Preme a icona de desbloquear."</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"Usouse o desbloqueo facial. Toca para continuar."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autenticado"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"Cancelar a autenticación"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"Máis opcións"</string>
@@ -478,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Engadir máis widgets"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Pulsación longa para personalizar os widgets"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Personalizar widgets"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"Desbloquea o dispositivo para personalizar os widgets"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Icona da aplicación de widget desactivado"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Icona da aplicación para un widget que se está instalando"</string>
<string name="edit_widget" msgid="9030848101135393954">"Editar widget"</string>
@@ -1378,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Volver"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"Para volver, pasa tres dedos cara á esquerda ou cara á dereita en calquera lugar do panel táctil."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"Panel táctil que mostra tres dedos movéndose á dereita e á esquerda"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index cedcaa1ca7bd..5e384e3a0779 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -103,8 +103,7 @@
<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>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"નોંધમાં ઉમેરો"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"લિંક શામેલ કરો"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"સ્ક્રીન રેકોર્ડર"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"સ્ક્રીન રેકૉર્ડિંગ ચાલુ છે"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"સ્ક્રીન રેકોર્ડિંગ સત્ર માટે ચાલુ નોટિફિકેશન"</string>
@@ -196,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"ચહેરા દ્વારા અનલૉક કર્યું. આગળ વધવા માટે દબાવો."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"ચહેરો ઓળખ્યો. આગળ વધવા માટે દબાવો."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"ચહેરો ઓળખ્યો. આગળ વધવા \'અનલૉક કરો\' આઇકન દબાવો."</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"ચહેરા દ્વારા અનલૉક કર્યું. ચાલુ રાખવા માટે ટૅપ કરો."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"પ્રમાણિત"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"પ્રમાણીકરણ રદ કરો"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"વધુ વિકલ્પો"</string>
@@ -478,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"વધુ વિજેટ ઉમેરો"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"વિજેટ કસ્ટમાઇઝ કરવા માટે થોડીવાર દબાવી રાખો"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"વિજેટ કસ્ટમાઇઝ કરો"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"વિજેટ કસ્ટમાઇઝ કરવા માટે, અનલૉક કરો"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"બંધ કરેલા વિજેટ માટેની ઍપનું આઇકન"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"ઇન્સ્ટૉલ થઈ રહેલા વિજેટ માટે ઍપનું આઇકન"</string>
<string name="edit_widget" msgid="9030848101135393954">"વિજેટમાં ફેરફાર કરો"</string>
@@ -1378,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"પાછા જાઓ"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"પાછા જવા માટે, ત્રણ આંગળીઓનો ઉપયોગ કરીને ટચપૅડ પર કોઈપણ જગ્યાએ ડાબે કે જમણે સ્વાઇપ કરો."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"જમણી અને ડાબી તરફ ખસી રહેલી ત્રણ આંગળીઓ બતાવતું ટચપૅડ"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 591ad1092dc4..54bcede8ef20 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -476,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"ज़्यादा विजेट जोड़ें"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"विजेट पसंद के मुताबिक बनाने के लिए उसे दबाकर रखें"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"विजेट अपनी पसंद के मुताबिक बनाएं"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"विजेट को पसंद के मुताबिक बनाने के लिए, डिवाइस अनलॉक करें"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"बंद किए गए विजेट के लिए ऐप्लिकेशन आइकॉन"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"इंस्टॉल हो रहे विजेट के लिए ऐप्लिकेशन आइकॉन"</string>
<string name="edit_widget" msgid="9030848101135393954">"विजेट में बदलाव करें"</string>
@@ -1376,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"वापस जाएं"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"वापस जाने के लिए, टचपैड पर कहीं भी तीन उंगलियों से बाईं या दाईं तरफ़ स्वाइप करें."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"टचपैड पर तीन उंगलियों को दाईं और बाईं तरफ़ ले जाया जा रहा है"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 372363dbda64..cac83e6abe91 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -103,8 +103,7 @@
<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>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Dodaj bilješci"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"Uključi vezu"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Snimač zaslona"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Obrada snimanja zaslona"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Tekuća obavijest za sesiju snimanja zaslona"</string>
@@ -196,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Otključano pomoću lica. Pritisnite da biste nastavili."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Lice je prepoznato. Pritisnite da biste nastavili."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Lice je prepoznato. Pritisnite ikonu otključavanja da biste nastavili."</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"Otključano licem. Dodirnite za nastavak."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autentifikacija izvršena"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"Otkaži autentifikaciju"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"Više opcija"</string>
@@ -478,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Dodavanje još widgeta"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Dugo pritisnite za prilagodbu widgeta"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Prilagodi widgete"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"Otključajte da biste prilagodili widgete"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Ikona aplikacije za onemogućeni widget"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Ikona aplikacije za widget koji se instalira"</string>
<string name="edit_widget" msgid="9030848101135393954">"Uredi widget"</string>
@@ -1378,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Natrag"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"Za povratak trima prstima prijeđite ulijevo ili udesno bilo gdje na dodirnoj podlozi."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"Dodirna podloga prikazuje tri prsta koji se kreću udesno i ulijevo"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 7c6566fdfb9b..c408e30cb322 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -103,8 +103,7 @@
<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>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Hozzáadás jegyzethez"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"Linkkel együtt"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Képernyőrögzítő"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Képernyőrögzítés feldolgozása"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Folyamatban lévő értesítés képernyőrögzítési munkamenethez"</string>
@@ -134,8 +133,7 @@
<string name="screenrecord_stop_dialog_message_specific_app" msgid="5285148796772616326">"Le fogja állítani a(z) &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; rögzítését"</string>
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
- <!-- no translation found for share_to_app_chip_accessibility_label (4210256229976947065) -->
- <skip />
+ <string name="share_to_app_chip_accessibility_label" msgid="4210256229976947065">"Képernyő megosztása…"</string>
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
@@ -143,8 +141,7 @@
<string name="share_to_app_stop_dialog_message_specific_app" msgid="124371406810544777">"Le fogja állítani a(z) &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; megosztását"</string>
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
- <!-- no translation found for cast_to_other_device_chip_accessibility_label (1680650146639059938) -->
- <skip />
+ <string name="cast_to_other_device_chip_accessibility_label" msgid="1680650146639059938">"Képernyőtartalom átküldése…"</string>
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
@@ -198,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Zárolás arccal feloldva. Koppintson a folytatáshoz."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Arc felismerve. Koppintson a folytatáshoz."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Arc felismerve. A folytatáshoz koppintson a Feloldásra."</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"Zárolás arccal feloldva. Koppintson a folytatáshoz."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Hitelesítve"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"Hitelesítés megszakítása"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"További lehetőségek"</string>
@@ -480,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"További modulok hozzáadása"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Nyomja meg hosszan a modulok személyre szabásához"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Modulok személyre szabása"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"A feloldással személyre szabhatja a modulokat"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Letiltott modul alkalmazásikonja"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Folyamatban van egy modul alkalmazásikonjának telepítése"</string>
<string name="edit_widget" msgid="9030848101135393954">"Modul szerkesztése"</string>
@@ -1359,15 +1354,11 @@
<string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"Használatban a következő által: <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string>
<string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"Legutóbb használta: <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string>
<string name="shortcut_helper_category_system" msgid="462110876978937359">"Rendszer"</string>
- <!-- no translation found for shortcut_helper_category_system_controls (3153344561395751020) -->
- <skip />
- <!-- no translation found for shortcut_helper_category_system_apps (6001757545472556810) -->
- <skip />
+ <string name="shortcut_helper_category_system_controls" msgid="3153344561395751020">"Rendszervezérlők"</string>
+ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Rendszeralkalmazások"</string>
<string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitasking"</string>
- <!-- no translation found for shortcutHelper_category_recent_apps (7918731953612377145) -->
- <skip />
- <!-- no translation found for shortcutHelper_category_split_screen (1159669813444812244) -->
- <skip />
+ <string name="shortcutHelper_category_recent_apps" msgid="7918731953612377145">"Legutóbbi alkalmazások"</string>
+ <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Osztott képernyő"</string>
<string name="shortcut_helper_category_input" msgid="8674018654124839566">"Bevitel"</string>
<string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Alkalmazás-parancsikonok"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Kisegítő lehetőségek"</string>
@@ -1384,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Vissza"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"A visszalépéshez csúsztasson három ujjal gyorsan balra vagy a jobbra az érintőpad tetszőleges területén."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"Három, jobbra és balra mozgó ujjat ábrázoló érintőpad"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index b00328a3b260..c898fca37433 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -103,8 +103,7 @@
<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>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Ավելացնել նշմանը"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"Ներառել հղումը"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Էկրանի տեսագրում"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Էկրանի տեսագրության մշակում"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Էկրանի տեսագրման աշխատաշրջանի ընթացիկ ծանուցում"</string>
@@ -196,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Ապակողպվել է դեմքով։ Սեղմեք շարունակելու համար։"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Դեմքը ճանաչվեց։ Սեղմեք շարունակելու համար։"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Դեմքը ճանաչվեց։ Սեղմեք ապակողպման պատկերակը։"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"Ապակողպվել է դեմքով։ Հպեք շարունակելու համար:"</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Նույնականացված է"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"Չեղարկել իսկորոշումը"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"Լրացուցիչ ընտրանքներ"</string>
@@ -478,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Ավելացնել վիջեթներ"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Երկար սեղմեք՝ վիջեթները հարմարեցնելու համար"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Հարմարեցնել վիջեթները"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"Ապակողպեք՝ վիջեթներն անհատականացնելու համար"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Հավելվածի պատկերակ անջատված վիջեթի համար"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Տեղադրվող վիջեթի հավելվածի պատկերակ"</string>
<string name="edit_widget" msgid="9030848101135393954">"Փոփոխել վիջեթը"</string>
@@ -1378,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Հետ գնալ"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"Հետ գնալու համար հպահարթակի վրա երեք մատով սահեցրեք ձախ կամ աջ։"</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"Երեք մատները աջ ու ձախ են շարժվում հպահարթակի վրա"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index b2352363826c..9546cf0abf8e 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -103,8 +103,7 @@
<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>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Tambahkan ke catatan"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"Sertakan link"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Perekam Layar"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Memproses perekaman layar"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notifikasi yang sedang berjalan untuk sesi rekaman layar"</string>
@@ -196,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Kunci dibuka dengan wajah. Tekan untuk melanjutkan."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Wajah dikenali. Tekan untuk melanjutkan."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Wajah dikenali. Tekan ikon buka kunci untuk melanjutkan."</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"Kunci dibuka dengan wajah. Ketuk untuk melanjutkan."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Diautentikasi"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"Batalkan Autentikasi"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"Opsi Lainnya"</string>
@@ -478,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Tambahkan widget lainnya"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Tekan lama untuk menyesuaikan widget"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Sesuaikan widget"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"Buka kunci untuk menyesuaikan widget"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Ikon aplikasi untuk widget yang dinonaktifkan"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Ikon aplikasi untuk widget yang sedang diinstal"</string>
<string name="edit_widget" msgid="9030848101135393954">"Edit widget"</string>
@@ -1378,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Kembali"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"Untuk kembali, geser ke kiri atau ke kanan menggunakan tiga jari ke mana saja di touchpad."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"Touchpad menampilkan tiga jari yang bergerak ke kanan dan ke kiri"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index ff5f3b8e759a..a6c7f88d77b5 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -103,8 +103,7 @@
<string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> greindi skjámyndina."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> og önnur opin forrit greindu skjámyndina."</string>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Bæta við glósu"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"Hafa tengil með"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Skjáupptaka"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Vinnur úr skjáupptöku"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Áframhaldandi tilkynning fyrir skjáupptökulotu"</string>
@@ -196,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Opnað með andliti. Ýttu til að halda áfram."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Andlitið var greint. Ýttu til að halda áfram."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Andlitið var greint. Ýttu á opnunartáknið til að halda áfr."</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"Opnað með andliti. Ýttu til að halda áfram."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Auðkennt"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"Hætta við auðkenningu"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"Fleiri valkostir"</string>
@@ -478,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Bæta við fleiri græjum"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Haltu inni til að sérsníða græjur"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Sérsníða græjur"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"Opnaðu til að sérsníða græjur"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Forritstákn fyrir græju sem slökkt er á"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Forritatákn fyrir græju sem verið er að setja upp"</string>
<string name="edit_widget" msgid="9030848101135393954">"Breyta græju"</string>
@@ -557,7 +554,7 @@
<string name="media_projection_action_text" msgid="3634906766918186440">"Byrja núna"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Engar tilkynningar"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"Engar nýjar tilkynningar"</string>
- <string name="adaptive_notification_edu_hun_title" msgid="5720882373252389461">"Kveikt er á breytilegum tilkynningum"</string>
+ <string name="adaptive_notification_edu_hun_title" msgid="5720882373252389461">"Kveikt á breytil. tilkynningum"</string>
<string name="adaptive_notification_edu_hun_text" msgid="4260536236101821273">"Tækið þitt lækkar nú hljóðstyrkinn og fækkar sprettigluggum á skjánum í allt að tvær mínútur þegar þú færð margar tilkynningar á stuttum tíma."</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"Slökkva"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Taktu úr lás til að sjá eldri tilkynningar"</string>
@@ -1378,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Til baka"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"Strjúktu til vinstri eða hægri með þrem fingrum hvar sem er á snertifletinum til að fara til baka."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"Snertiflötur sem sýnir þrjá fingur færast til hægri og vinstri"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 90d55f70a23b..606732909862 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -476,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Aggiungi altri widget"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Premi a lungo per personalizzare i widget"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Personalizza widget"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"Sblocca per personalizzare i widget"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Icona dell\'app per widget disattivati"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Icona dell\'app per un widget in fase di installazione"</string>
<string name="edit_widget" msgid="9030848101135393954">"Modifica widget"</string>
@@ -1376,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Indietro"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"Per tornare indietro, scorri verso sinistra o verso destra utilizzando tre dita in un punto qualsiasi del touchpad."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"Touchpad che mostra tre dita che si muovono verso destra e sinistra"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index c5940805961e..fba992089afe 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -476,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"הוספת ווידג\'טים"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"לוחצים לחיצה ארוכה כדי להתאים אישית את הווידג\'טים"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"התאמה אישית של ווידג\'טים"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"כדי להתאים אישית את הווידג\'טים, צריך לבטל את הנעילה"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"סמל האפליקציה לווידג\'ט שהושבת"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"סמל האפליקציה של ווידג\'ט בתהליך התקנה"</string>
<string name="edit_widget" msgid="9030848101135393954">"עריכת הווידג\'ט"</string>
@@ -1376,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"חזרה"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"כדי לחזור אחורה, מחליקים שמאלה או ימינה עם שלוש אצבעות בכל מקום על לוח המגע."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"לוח מגע שמראה שלוש אצבעות זזות ימינה ושמאלה"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index da357011f1f1..5a5701674b47 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -476,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"ウィジェットの追加"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"長押ししてウィジェットをカスタマイズ"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"ウィジェットのカスタマイズ"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"ウィジェットをカスタマイズするにはロックを解除してください"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"無効なウィジェットのアプリアイコン"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"インストール中のウィジェットのアプリアイコン"</string>
<string name="edit_widget" msgid="9030848101135393954">"ウィジェットを編集"</string>
@@ -1376,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"戻る"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"戻るには、3 本の指でタッチパッドを左右にスワイプします。"</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"タッチパッドで 3 本の指を左右に動かしている様子"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 977fed796d43..dd92fee61f9d 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -476,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"ვიჯეტების დამატება"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"ხანგრძლივად დააჭირეთ ვიჯეტების მოსარგებად"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"ვიჯეტების მორგება"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"ვიჯეტების მოსარგებად განბლოკეთ"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"აპის ხატულა გათიშული ვიჯეტისთვის"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"ინსტალაციის პროცესში მყოფი ვიჯეტის აპის ხატულა"</string>
<string name="edit_widget" msgid="9030848101135393954">"ვიჯეტის რედაქტირება"</string>
@@ -1376,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"უკან დაბრუნება"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"უკან დასაბრუნებლად, სენსორულ პანელზე ნებისმიერ ადგილას სამი თითის გამოყენებით გადაფურცლეთ მარცხნივ ან მარჯვნივ."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"სენსორული პანელი, რომელიც აჩვენებს მარჯვენა და მარცხენა მიმართულებით მოძრავ სამ თითს"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 3df7fc16fb12..2c7d43d6d78e 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -103,8 +103,7 @@
<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>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Ескертпеге қосу"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"Сілтеме қосу"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Экран жазғыш"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Экран жазғыш бейнесін өңдеу"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Экранды бейнеге жазудың ағымдағы хабарландыруы"</string>
@@ -196,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Бетпен ашылды. Жалғастыру үшін басыңыз."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Бет танылды. Жалғастыру үшін басыңыз."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Бет танылды. Жалғастыру үшін құлыпты ашу белгішесін басыңыз."</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"Бетпен ашылды. Жалғастыру үшін түртіңіз."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Аутентификацияланған"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"Аутентификациядан бас тарту"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"Қосымша опциялар"</string>
@@ -478,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Басқа виджеттер қосыңыз."</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Виджеттерді бейімдеу үшін ұзақ басып тұрыңыз."</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Виджеттерді реттеу"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"Виджеттерді бейімдеу үшін құлыпты ашыңыз."</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Өшірілген виджеттің қолданба белгішесі"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Виджетке арналған қолдана белгішесі орнатылып жатыр."</string>
<string name="edit_widget" msgid="9030848101135393954">"Виджетті өзгерту"</string>
@@ -1378,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Артқа"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"Артқа қайту үшін сенсорлық тақтаның кез келген жерінен үш саусақпен солға немесе оңға сырғытыңыз."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"Оңға және солға жылжитын үш саусақты көрсетіп тұрған сенсорлық тақта."</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 303410d70927..e16225bdcfb3 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -103,8 +103,7 @@
<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>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"បញ្ចូលទៅក្នុងកំណត់ចំណាំ"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"រួមបញ្ចូល​តំណ"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"មុខងារថត​វីដេអូអេក្រង់"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"កំពុង​ដំណើរការ​ការថតអេក្រង់"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"ការជូនដំណឹង​ដែល​កំពុង​ដំណើរការ​សម្រាប់​រយៈពេលប្រើ​ការថត​សកម្មភាព​អេក្រង់"</string>
@@ -196,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"បានដោះសោដោយប្រើមុខ។ សូមចុច ដើម្បីបន្ត។"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"បានស្គាល់មុខ។ សូមចុច ដើម្បីបន្ត។"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"បានស្គាល់មុខ។ សូមចុចរូបដោះសោ ដើម្បីបន្ត។"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"បានដោះសោដោយប្រើមុខ។ ចុច​ ដើម្បី​បន្ត។"</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"បាន​ផ្ទៀងផ្ទាត់"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"បោះបង់ការផ្ទៀងផ្ទាត់"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"ជម្រើស​ច្រើន​ទៀត"</string>
@@ -478,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"បញ្ចូលធាតុ​ក្រាហ្វិកច្រើនទៀត"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"ចុច​ឱ្យ​យូរ ដើម្បីប្ដូរធាតុ​ក្រាហ្វិកតាមបំណង"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"ប្ដូរ​ធាតុ​ក្រាហ្វិកតាម​បំណង"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"ដោះសោ​ដើម្បីប្ដូរធាតុ​ក្រាហ្វិកតាមបំណង"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"រូបកម្មវិធីសម្រាប់ធាតុ​ក្រាហ្វិកដែលបានបិទ"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"រូបតំណាងកម្មវិធីសម្រាប់ធាតុ​ក្រាហ្វិកកំពុងត្រូវបានដំឡើង"</string>
<string name="edit_widget" msgid="9030848101135393954">"កែធាតុ​ក្រាហ្វិក"</string>
@@ -1378,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"ថយ​ក្រោយ"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"ដើម្បីថយក្រោយ សូមអូសទៅឆ្វេង ឬស្ដាំដោយប្រើម្រាមដៃបីនៅកន្លែងណាមួយនៅលើផ្ទាំងប៉ះ។"</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"ផ្ទាំងប៉ះដែលបង្ហាញម្រាមដៃបីដែលផ្លាស់ទីទៅស្ដាំ និងឆ្វេង"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 4af252d9e3cb..24f5bb5c2629 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -476,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"ಹೆಚ್ಚಿನ ವಿಜೆಟ್‌ಗಳನ್ನು ಸೇರಿಸಿ"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"ವಿಜೆಟ್‌ಗಳನ್ನು ಕಸ್ಟಮೈಸ್ ಮಾಡಲು ದೀರ್ಘಕಾಲ ಒತ್ತಿರಿ"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"ವಿಜೆಟ್‌ಗಳನ್ನು ಕಸ್ಟಮೈಸ್ ಮಾಡಿ"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"ವಿಜೆಟ್‌ಗಳನ್ನು ಕಸ್ಟಮೈಸ್ ಮಾಡಲು ಅನ್‌ಲಾಕ್ ಮಾಡಿ"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾದ ವಿಜೆಟ್‌ಗಾಗಿ ಆ್ಯಪ್ ಐಕಾನ್"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"ಇನ್‌ಸ್ಟಾಲ್ ಮಾಡಲಾದ ವಿಜೆಟ್‌ಗಾಗಿ ಆ್ಯಪ್ ಐಕಾನ್"</string>
<string name="edit_widget" msgid="9030848101135393954">"ವಿಜೆಟ್ ಅನ್ನು ಎಡಿಟ್ ಮಾಡಿ"</string>
@@ -1376,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"ಹಿಂತಿರುಗಿ"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"ಹಿಂತಿರುಗಲು, ಟಚ್‌ಪ್ಯಾಡ್‌ನಲ್ಲಿ ಎಲ್ಲಿಯಾದರೂ ಮೂರು ಬೆರಳುಗಳನ್ನು ಬಳಸಿ ಎಡ ಅಥವಾ ಬಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"ಮೂರು ಬೆರಳುಗಳು ಬಲಕ್ಕೆ ಮತ್ತು ಎಡಕ್ಕೆ ಚಲಿಸುತ್ತಿರುವುದನ್ನು ತೋರಿಸುತ್ತಿರುವ ಟಚ್‌ಪ್ಯಾಡ್"</string>
diff --git a/packages/SystemUI/res/values-kn/tiles_states_strings.xml b/packages/SystemUI/res/values-kn/tiles_states_strings.xml
index afc7c1a10e0e..c7cb2b16a2f3 100644
--- a/packages/SystemUI/res/values-kn/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-kn/tiles_states_strings.xml
@@ -188,7 +188,7 @@
</string-array>
<string-array name="tile_states_hearing_devices">
<item msgid="1235334096484287173">"ಲಭ್ಯವಿಲ್ಲ"</item>
- <item msgid="3079622119444911877">"ಆಫ್ ಆಗಿದೆ"</item>
+ <item msgid="3079622119444911877">"ಆಫ್"</item>
<item msgid="3028994095749238254">"ಆನ್"</item>
</string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index dc1ebf1b2da9..89acb429332f 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -103,8 +103,7 @@
<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>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"메모에 추가"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"링크 포함"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"화면 녹화"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"화면 녹화 처리 중"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"화면 녹화 세션에 관한 지속적인 알림"</string>
@@ -196,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"얼굴 인식으로 잠금 해제되었습니다. 계속하려면 누르세요."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"얼굴이 인식되었습니다. 계속하려면 누르세요."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"얼굴이 인식되었습니다. 계속하려면 아이콘을 누르세요."</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"얼굴 인식으로 잠금 해제되었습니다. 계속하려면 탭하세요."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"인증됨"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"인증 취소"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"옵션 더보기"</string>
@@ -478,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"더 많은 위젯 추가"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"위젯을 맞춤설정하려면 길게 누르기"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"위젯 맞춤설정"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"위젯을 맞춤설정하려면 잠금 해제하세요."</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"사용 중지된 위젯의 앱 아이콘"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"설치 중인 위젯의 앱 아이콘"</string>
<string name="edit_widget" msgid="9030848101135393954">"위젯 수정"</string>
@@ -1378,10 +1375,12 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"뒤로"</string>
- <string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"돌아가려면 터치패드의 아무 곳이나 세 손가락으로 왼쪽 또는 오른쪽으로 스와이프합니다."</string>
+ <string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"돌아가려면 세 손가락을 사용해 터치패드의 아무 곳이나 왼쪽 또는 오른쪽으로 스와이프합니다."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"터치패드에서 세 손가락을 좌우로 움직이는 모습"</string>
- <string name="touchpad_back_gesture_screen_animation_content_description" msgid="4036267494237748710">"뒤로 동작 애니메이션이 표시된 기기 화면"</string>
+ <string name="touchpad_back_gesture_screen_animation_content_description" msgid="4036267494237748710">"뒤로 동작 애니메이션을 보여 주는 기기 화면"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"키보드 백라이트"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$d단계 중 %1$d단계"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"홈 컨트롤"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 9a4920152b60..db6816ac3764 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -103,8 +103,7 @@
<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>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Кыска жазууга кошуу"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"Шилтеме кошуу"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Экрандан видео жаздырып алуу"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Экрандан жаздырылып алынган видео иштетилүүдө"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Экранды жаздыруу сеансы боюнча учурдагы билдирме"</string>
@@ -196,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Кулпуну жүзүңүз менен ачтыңыз. Улантуу үчүн басыңыз."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Жүз таанылды. Улантуу үчүн басыңыз."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Жүз таанылды. Улантуу үчүн кулпусун ачуу сүрөтчөсүн басыңыз."</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"Кулпусун жүзүңүз менен ачтыңыз. Улантуу үчүн таптап коюңуз."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Аныктыгы текшерилди"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"Аныктыгын текшерүүнү жокко чыгаруу"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"Дагы параметрлер"</string>
@@ -478,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Көбүрөөк виджеттерди кошуу"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Виджеттерди ыңгайлаштыруу үчүн кое бербей басып туруңуз"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Виджеттерди ыңгайлаштыруу"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"Виджеттерди ыңгайлаштыруу үчүн кулпуну ачыңыз"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Өчүрүлгөн виджет үчүн колдонмонун сүрөтчөсү"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Виджет үчүн колдонмонун сүрөтчөсү орнотулууда"</string>
<string name="edit_widget" msgid="9030848101135393954">"Виджетти түзөтүү"</string>
@@ -1378,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Артка кайтуу"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"Кайтуу үчүн сенсордук тактанын каалаган жерин үч манжаңыз менен солго же оңго сүрүңүз."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"Үч манжанын оңго жана солго жылып жатканы көрсөтүлгөн сенсордук такта"</string>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 22dcbe266ae3..7652e4bb4f91 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -103,8 +103,7 @@
<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>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"ເພີ່ມໃສ່ບັນທຶກ"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"ຮວມລິ້ງ"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"ໂປຣແກຣມບັນທຶກໜ້າຈໍ"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"ກຳລັງປະມວນຜົນການບັນທຶກໜ້າຈໍ"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"ການແຈ້ງເຕືອນສຳລັບເຊດຊັນການບັນທຶກໜ້າຈໍໃດໜຶ່ງ"</string>
@@ -196,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"ປົດລັອກດ້ວຍໜ້າແລ້ວ. ກົດເພື່ອສືບຕໍ່."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"ຈຳແນກໜ້າໄດ້ແລ້ວ. ກົດເພື່ອສືບຕໍ່."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"ຈຳແນກໜ້າໄດ້ແລ້ວ. ກົດໄອຄອນປົດລັອກເພື່ອສືບຕໍ່."</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"ປົດລັອກດ້ວຍໃບໜ້າແລ້ວ. ແຕະເພື່ອສືບຕໍ່."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"ຮັບຮອງຄວາມຖືກຕ້ອງແລ້ວ"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"ຍົກເລີກການພິສູດຢືນຢັນ"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"ຕົວເລືອກເພີ່ມເຕີມ"</string>
@@ -478,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"ເພີ່ມວິດເຈັດເພີ່ມເຕີມ"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"ກົດຄ້າງໄວ້ເພື່ອປັບແຕ່ງວິດເຈັດ"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"ປັບແຕ່ງວິດເຈັດ"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"ປົດລັອກເພື່ອປັບແຕ່ງວິດເຈັດ"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"ໄອຄອນແອັບສຳລັບວິດເຈັດທີ່ຖືກປິດການນຳໃຊ້"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"ກຳລັງຕິດຕັ້ງໄອຄອນແອັບສຳລັບວິດເຈັດ"</string>
<string name="edit_widget" msgid="9030848101135393954">"ແກ້ໄຂວິດເຈັດ"</string>
@@ -1378,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"ກັບຄືນ"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"ເພື່ອກັບຄືນ, ໃຫ້ໃຊ້ 3 ນິ້ວປັດຊ້າຍ ຫຼື ຂວາບ່ອນໃດກໍໄດ້ເທິງແຜ່ນສໍາຜັດ."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"ແຜ່ນສໍາຜັດສະແດງພາບ 3 ນິ້ວເລື່ອນໄປທາງຂວາ ແລະ ຊ້າຍ"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index eef54d1ace10..2787a84651c9 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -103,8 +103,7 @@
<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>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Pridėti prie užrašo"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"Įtraukti nuorodą"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Ekrano vaizdo įrašytuvas"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Apdorojam. ekrano vaizdo įraš."</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Šiuo metu rodomas ekrano įrašymo sesijos pranešimas"</string>
@@ -196,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Atrakinta pagal veidą. Paspauskite, jei norite tęsti."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Veidas atpažintas. Paspauskite, jei norite tęsti."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Veidas atpažintas. Tęskite paspaudę atrakinimo piktogramą."</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"Atrakinta pagal veidą. Palieskite ir tęskite."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autentifikuota"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"Atšaukti autentifikavimą"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"Daugiau parinkčių"</string>
@@ -478,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Pridėkite daugiau valdiklių"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Ilgai paspauskite, kad tinkintumėte valdiklius"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Tinkinti valdiklius"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"Atrakinkite, kad galėtumėte tinkinti valdiklius"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Išjungto valdiklio programos piktograma"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Įdiegiamo valdiklio programos piktograma"</string>
<string name="edit_widget" msgid="9030848101135393954">"Redaguoti valdiklį"</string>
@@ -1378,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Grįžti"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"Jei norite grįžti, trimis pirštais perbraukite kairėn arba dešinėn bet kurioje jutiklinės dalies vietoje."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"Jutiklinė dalis, kurioje rodomi trys dešinėn ir kairėn judantys pirštai"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 5accf6a4915c..76d943fed7c5 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -103,8 +103,7 @@
<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>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Pievienot piezīmei"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"Iekļaut saiti"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Ekrāna ierakstītājs"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Ekrāna ieraksta apstrāde"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Aktīvs paziņojums par ekrāna ierakstīšanas sesiju"</string>
@@ -196,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Ierīce atbloķēta ar seju. Nospiediet, lai turpinātu."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Seja atpazīta. Nospiediet, lai turpinātu."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Seja atpazīta. Lai turpinātu, nospiediet atbloķēšanas ikonu."</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"Ierīce atbloķēta pēc sejas. Pieskarieties, lai turpinātu."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autentifikācija veikta"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"Atcelt autentificēšanu"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"Citas opcijas"</string>
@@ -478,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Pievienot citus logrīkus"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Nospiediet un turiet, lai pielāgotu logrīkus."</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Pielāgot logrīkus"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"Atbloķējiet, lai pielāgotu logrīkus"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Lietotnes ikona atspējotam logrīkam"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Tiek instalēta lietotnes ikona logrīkam."</string>
<string name="edit_widget" msgid="9030848101135393954">"Rediģēt logrīku"</string>
@@ -802,7 +799,7 @@
<string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"Nav atrasti"</string>
<string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"Sistēma"</string>
<string name="keyboard_shortcut_search_category_input" msgid="5440558509904296233">"Ievade"</string>
- <string name="keyboard_shortcut_search_category_open_apps" msgid="1450959949739257562">"Atvērtās"</string>
+ <string name="keyboard_shortcut_search_category_open_apps" msgid="1450959949739257562">"Atvērtās lietotnes"</string>
<string name="keyboard_shortcut_search_category_current_app" msgid="2011953559133734491">"Pašreizējā"</string>
<string name="keyboard_shortcut_a11y_show_search_results" msgid="2865241062981833705">"Tiek rādīti meklēšanas rezultāti"</string>
<string name="keyboard_shortcut_a11y_filter_system" msgid="7744143131119370483">"Tiek rādīti sistēmas īsinājumtaustiņi"</string>
@@ -1378,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Atpakaļ"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"Lai pārietu atpakaļ, ar trim pirkstiem velciet pa kreisi vai pa labi jebkurā vietā uz skārienpaliktņa"</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"Attēls ar skārienpaliktni, uz kura trīs pirksti kustas pa labi un pa kreisi"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index d121b9dd6acc..2d2718173021 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -103,8 +103,7 @@
<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>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Додај во белешка"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"Опфати линк"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Снимач на екран"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Се обработува снимка од екран"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Тековно известување за сесија за снимање на екранот"</string>
@@ -134,8 +133,7 @@
<string name="screenrecord_stop_dialog_message_specific_app" msgid="5285148796772616326">"Ќе го сопрете снимањето на &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;"</string>
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
- <!-- no translation found for share_to_app_chip_accessibility_label (4210256229976947065) -->
- <skip />
+ <string name="share_to_app_chip_accessibility_label" msgid="4210256229976947065">"Се споделува екранот"</string>
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
@@ -143,8 +141,7 @@
<string name="share_to_app_stop_dialog_message_specific_app" msgid="124371406810544777">"Ќе го сопрете споделувањето на &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;"</string>
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
- <!-- no translation found for cast_to_other_device_chip_accessibility_label (1680650146639059938) -->
- <skip />
+ <string name="cast_to_other_device_chip_accessibility_label" msgid="1680650146639059938">"Се емитува екранот"</string>
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
@@ -198,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Отклучено со лик. Притиснете за да продолжите."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Лицето е препознаено. Притиснете за да продолжите."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Лицето е препознаено. Притиснете ја иконата за отклучување за да продолжите."</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"Отклучено со лик. Допрете за да продолжите."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Проверена"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"Откажување автентикација"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"Повеќе опции"</string>
@@ -480,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Додајте повеќе виџети"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Притиснете долго за да ги приспособите виџетите"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Приспособете ги виџетите"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"Отклучете за да ги приспособите виџетите"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Икона за апликација за оневозможен виџет"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Икона за апликација за виџет што се инсталира"</string>
<string name="edit_widget" msgid="9030848101135393954">"Изменување виџети"</string>
@@ -1359,15 +1354,11 @@
<string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"Се користи од <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string>
<string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"Неодамна користено од <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string>
<string name="shortcut_helper_category_system" msgid="462110876978937359">"Систем"</string>
- <!-- no translation found for shortcut_helper_category_system_controls (3153344561395751020) -->
- <skip />
- <!-- no translation found for shortcut_helper_category_system_apps (6001757545472556810) -->
- <skip />
+ <string name="shortcut_helper_category_system_controls" msgid="3153344561395751020">"Системски контроли"</string>
+ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Системски апликации"</string>
<string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Мултитаскинг"</string>
- <!-- no translation found for shortcutHelper_category_recent_apps (7918731953612377145) -->
- <skip />
- <!-- no translation found for shortcutHelper_category_split_screen (1159669813444812244) -->
- <skip />
+ <string name="shortcutHelper_category_recent_apps" msgid="7918731953612377145">"Неодамнешни апликации"</string>
+ <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Поделен екран"</string>
<string name="shortcut_helper_category_input" msgid="8674018654124839566">"Внесување"</string>
<string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Кратенки за апликации"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Пристапност"</string>
@@ -1384,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Назад"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"За да се вратите назад, повлечете налево или надесно со три прста каде било на допирната подлога."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"Допирната подлога покажува три прста што се движат десно и лево"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 0bc502870555..3c9918433fe9 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -103,8 +103,7 @@
<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>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"കുറിപ്പിലേക്ക് ചേർക്കുക"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"ലിങ്ക് ഉൾപ്പെടുത്തുക"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"സ്ക്രീൻ റെക്കോർഡർ"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"സ്ക്രീൻ റെക്കോർഡിംഗ് പ്രോസസുചെയ്യുന്നു"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"ഒരു സ്ക്രീൻ റെക്കോർഡിംഗ് സെഷനായി നിലവിലുള്ള അറിയിപ്പ്"</string>
@@ -196,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"മുഖം ഉപയോഗിച്ച് അൺലോക്ക് ചെയ്‌തു. തുടരാൻ അമർത്തുക."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"മുഖം തിരിച്ചറിഞ്ഞു. തുടരാൻ അമർത്തുക."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"മുഖം തിരിച്ചറിഞ്ഞു. തുടരാൻ അൺലോക്ക് ഐക്കൺ അമർത്തുക."</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"മുഖം വഴി അൺലോക്കുചെയ്തു. തുടരാൻ ടാപ്പ് ചെയ്യുക."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"പരിശോധിച്ചുറപ്പിച്ചു"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"പരിശോധിച്ചുറപ്പിക്കൽ റദ്ദാക്കുക"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"കൂടുതൽ ഓപ്‌ഷനുകൾ"</string>
@@ -478,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"കൂടുതൽ വിജറ്റുകൾ ചേർക്കുക"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"വിജറ്റുകൾ ഇഷ്ടാനുസൃതമാക്കാൻ ദീർഘനേരം അമർത്തുക"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"വിജറ്റുകൾ ഇഷ്ടാനുസൃതമാക്കുക"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"വിജറ്റുകൾ ഇഷ്ടാനുസൃതമാക്കാൻ അൺലോക്ക് ചെയ്യുക"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"പ്രവർത്തനരഹിതമാക്കിയ വിജറ്റിനുള്ള ആപ്പ് ഐക്കൺ"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"വിജറ്റിനുള്ള ആപ്പ് ഐക്കൺ ഇൻസ്റ്റാൾ ചെയ്തു"</string>
<string name="edit_widget" msgid="9030848101135393954">"വിജറ്റ് എഡിറ്റ് ചെയ്യുക"</string>
@@ -1378,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"മടങ്ങുക"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"തിരികെ പോകാൻ, ടച്ച്പാഡിൽ എവിടെയെങ്കിലും മൂന്ന് വിരലുകൾ ഉപയോഗിച്ച് ഇടത്തേക്കോ വലത്തേക്കോ സ്വൈപ്പ് ചെയ്യുക."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"വലത്തേക്കും ഇടത്തേക്കും ചലിക്കുന്ന മൂന്ന് വിരലുകൾ കാണിക്കുന്ന ടച്ച്പാഡ്"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index be9bceef44a4..2f4adf615a4e 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -103,8 +103,7 @@
<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>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Тэмдэглэлд нэмэх"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"Холбоосыг оруулах"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Дэлгэцийн үйлдэл бичигч"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Дэлгэц бичлэг боловсруулж байна"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Дэлгэц бичих горимын үргэлжилж буй мэдэгдэл"</string>
@@ -196,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Царайгаар түгжээг тайлсан. Үргэлжлүүлэхийн тулд дарна уу."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Царайг таньсан. Үргэлжлүүлэхийн тулд дарна уу."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Царайг таньсан. Үргэлжлүүлэх бол түгжээг тайлах дүрсийг дар."</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"Царайгаар түгжээг тайлсан. Үргэлжлүүлэхийн тулд товшино уу."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Баталгаажуулагдсан"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"Баталгаажуулалтыг цуцлах"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"Бусад сонголт"</string>
@@ -478,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Илүү олон виджет нэмэх"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Виджетүүдийг өөрчлөхийн тулд удаан дарна уу"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Виджетүүдийг өөрчлөх"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"Виджетийг өөрчлөхийн тулд түгжээг тайлна уу"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Идэвхгүй болгосон виджетийн аппын дүрс тэмдэг"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Виджет суулгах явцын аппын дүрс тэмдэг"</string>
<string name="edit_widget" msgid="9030848101135393954">"Виджетийг засах"</string>
@@ -1378,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Буцах"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"Буцаж очихын тулд мэдрэгч самбар дээр гурван хуруугаараа хүссэн газраа зүүн эсвэл баруун тийш шударна уу."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"Гурван хуруу баруун болон зүүн тийш хөдөлж буйг харуулсан мэдрэгч самбар"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 302a685cb143..a5633a2fbd11 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -476,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"आणखी विजेट जोडा"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"विजेट कस्टमाइझ करण्यासाठी प्रेस करून ठेवा"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"विजेट कस्टमाइझ करा"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"विजेट कस्टमाइझ करण्यासाठी अनलॉक करा"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"बंद केलेल्या विजेटच्या अ‍ॅपचे आयकन"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"इंस्टॉल होत असलेल्या विजेटसाठी अ‍ॅपचा आयकन"</string>
<string name="edit_widget" msgid="9030848101135393954">"विजेट संपादित करा"</string>
@@ -1376,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"मागे जा"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"मागे जाण्यासाठी, टचपॅडवर कुठेही तीन बोटांनी डावीकडे किंवा उजवीकडे स्‍वाइप करा."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"तीन बोट उजवीकडे आणि डावीकडे हलताना दाखवणारे टचपॅड"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 11407f6cf684..984fe3a07ea0 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -476,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Tambahkan lagi widget"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Tekan lama untuk menyesuaikan widget"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Sesuaikan widget"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"Buka kunci untuk menyesuaikan widget"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Ikon apl untuk melumpuhkan widget"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Ikon apl untuk widget yang sedang dipasang"</string>
<string name="edit_widget" msgid="9030848101135393954">"Edit widget"</string>
@@ -1376,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Kembali"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"Untuk kembali, leret ke kiri atau kanan menggunakan tiga jari di mana-mana sahaja pada pad sentuh."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"Pad sentuh menunjukkan tiga jari bergerak ke kanan dan kiri"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 8f35ff676d35..c916e31bbcc8 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -476,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"နောက်ထပ်ဝိဂျက်များ ထည့်ရန်"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"ဝိဂျက်များ စိတ်ကြိုက်လုပ်ရန် ကြာကြာနှိပ်ထားပါ"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"ဝိဂျက်များကို စိတ်ကြိုက်လုပ်ရန်"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"ဝိဂျက်များ စိတ်ကြိုက်လုပ်ရန် ဖွင့်နိုင်သည်"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"ပိတ်ထားသော ဝိဂျက်အတွက် အက်ပ်သင်္ကေတ"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"ထည့်သွင်းနေသော ဝိဂျက်အတွက် အက်ပ်သင်္ကေတ"</string>
<string name="edit_widget" msgid="9030848101135393954">"ဝိဂျက်ပြင်ရန်"</string>
@@ -1376,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"ပြန်သွားရန်"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"ပြန်သွားရန်အတွက် တာ့ချ်ပက်တွင် မည်သည့်နေရာ၌မဆို လက်သုံးချောင်းသုံး၍ ဘယ် (သို့) ညာသို့ ပွတ်ဆွဲပါ။"</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"တာ့ချ်ပက်တွင် ဘယ်ညာရွှေ့နေသော လက်သုံးချောင်းကို ပြထားသည်"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index cc57e8abbd7e..8fccf1af0226 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -71,7 +71,7 @@
<string name="usb_port_enabled" msgid="531823867664717018">"Registrering av ladere og tilbehør er slått på for USB-porten"</string>
<string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"Slå på USB"</string>
<string name="learn_more" msgid="4690632085667273811">"Finn ut mer"</string>
- <string name="global_action_screenshot" msgid="2760267567509131654">"Skjermdump"</string>
+ <string name="global_action_screenshot" msgid="2760267567509131654">"Skjermbilde"</string>
<string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Hold ulåst er slått av"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"har sendt et bilde"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Lagrer skjermbildet …"</string>
@@ -103,8 +103,7 @@
<string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> har registrert dette skjermbildet."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> og andre åpne apper har registrert dette skjermbildet."</string>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Legg til i notat"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"Inkluder linken"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Skjermopptak"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Behandler skjermopptaket"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Vedvarende varsel for et skjermopptak"</string>
@@ -196,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Låst opp med ansiktet. Trykk for å fortsette."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Ansiktet er gjenkjent. Trykk for å fortsette."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Ansiktet er gjenkjent. Trykk på lås opp-ikon for å fortsette"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"Låst opp med ansiktet. Trykk for å fortsette."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autentisert"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"Avbryt autentisering"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"Flere alternativer"</string>
@@ -478,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Legg til flere moduler"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Trykk lenge for å tilpasse modulene"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Tilpass moduler"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"Lås opp for å tilpasse moduler"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Appikon for deaktivert modul"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Appikon for en modul som installeres"</string>
<string name="edit_widget" msgid="9030848101135393954">"Endre modul"</string>
@@ -1378,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Gå tilbake"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"For å gå tilbake, sveip til venstre eller høyre med tre fingre hvor som helst på styreflaten."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"En styreflate med tre fingre som beveger seg til høyre og venstre"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 6b353618a5ab..8fae08dede38 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -476,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"थप विजेटहरू हाल्नुहोस्"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"विजेटहरू कस्टमाइज गर्न केही बेरसम्म थिच्नुहोस्"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"विजेटहरू कस्टमाइज गर्नुहोस्"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"विजेटहरू कस्टमाइज गर्न अन लक गर्नुहोस्"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"अफ गरिएको विजेटको एप जनाउने आइकन"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"इन्स्टल भइरहेको विजेटको एप आइकन"</string>
<string name="edit_widget" msgid="9030848101135393954">"विजेट सम्पादन गर्नुहोस्"</string>
@@ -1376,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"पछाडि जानुहोस्"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"पछाडि जान तिन वटा औँलाले टचप्याडमा कतै छोएर बायाँ वा दायाँतिर स्वाइप गर्नुहोस्।"</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"तिन वटा औँला दायाँ र बायाँ सारेको देखाइएको टचप्याड"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 1bbb0e3702cd..6dbd8fbfbd9f 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -103,8 +103,7 @@
<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>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Toevoegen aan notitie"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"Link opnemen"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Schermopname"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Schermopname verwerken"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Doorlopende melding voor een schermopname-sessie"</string>
@@ -196,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Ontgrendeld via gezicht. Druk om door te gaan."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Gezicht herkend. Druk om door te gaan."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Gezicht herkend. Druk op het ontgrendelicoon."</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"Ontgrendeld via gezicht. Tik om door te gaan."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Geverifieerd"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"Verificatie annuleren"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"Meer opties"</string>
@@ -478,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Meer widgets toevoegen"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Houd lang ingedrukt om widgets aan te passen"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Widgets aanpassen"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"Ontgrendel om widgets aan te passen"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"App-icoon voor uitgezette widget"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"App-icoon voor een widget die wordt geïnstalleerd"</string>
<string name="edit_widget" msgid="9030848101135393954">"Widget bewerken"</string>
@@ -1378,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Terug"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"Als je wilt teruggaan, swipe je met 3 vingers naar links of rechts op de touchpad."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"Touchpad met 3 vingers die naar rechts en links bewegen"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index aaf94c9cdd58..0f0598296863 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -103,8 +103,7 @@
<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>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"ନୋଟରେ ଯୋଗ କରନ୍ତୁ"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"ଲିଙ୍କକୁ ଅନ୍ତର୍ଭୁକ୍ତ କରନ୍ତୁ"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"ସ୍କ୍ରିନ ରେକର୍ଡର"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"ସ୍କ୍ରିନ ରେକର୍ଡିଂର ପ୍ରକ୍ରିୟାକରଣ"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"ଏକ ସ୍କ୍ରି‍ନ୍‍ ରେକର୍ଡ୍‍ ସେସନ୍‍ ପାଇଁ ଚାଲୁଥିବା ବିଜ୍ଞପ୍ତି"</string>
@@ -196,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"ଫେସ ମାଧ୍ୟମରେ ଅନଲକ କରାଯାଇଛି। ଜାରି ରଖିବାକୁ ଦବାନ୍ତୁ।"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"ଫେସ ଚିହ୍ନଟ କରାଯାଇଛି। ଜାରି ରଖିବାକୁ ଦବାନ୍ତୁ।"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"ଫେସ ଚିହ୍ନଟ କରାଯାଇଛି। ଜାରି ରଖିବାକୁ ଅନଲକ ଆଇକନ ଦବାନ୍ତୁ।"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"ଫେସ ମାଧ୍ୟମରେ ଅନଲକ କରାଯାଇଛି। ଜାରି ରଖିବାକୁ ଟାପ କରନ୍ତୁ।"</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"ପ୍ରାମାଣିକତା ହୋଇଛି"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"ପ୍ରମାଣୀକରଣକୁ ବାତିଲ କରନ୍ତୁ"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"ଅଧିକ ବିକଳ୍ପ"</string>
@@ -478,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"ଅଧିକ ୱିଜେଟ ଯୋଗ କରନ୍ତୁ"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"ୱିଜେଟଗୁଡ଼ିକୁ କଷ୍ଟମାଇଜ କରିବା ପାଇଁ ଅଧିକ ସମୟ ଦବାନ୍ତୁ"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"ୱିଜେଟଗୁଡ଼ିକୁ କଷ୍ଟମାଇଜ କରନ୍ତୁ"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"ୱିଜେଟ କଷ୍ଟମାଇଜ କରିବାକୁ ଅନଲକ କରନ୍ତୁ"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"ଅକ୍ଷମ କରାଯାଇଥିବା ୱିଜେଟ ପାଇଁ ଆପ ଆଇକନ"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"ଏକ ୱିଜେଟ ପାଇଁ ଆପ ଆଇକନକୁ ଇନଷ୍ଟଲ କରାଯାଉଛି"</string>
<string name="edit_widget" msgid="9030848101135393954">"ୱିଜେଟକୁ ଏଡିଟ କରନ୍ତୁ"</string>
@@ -1378,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"ପଛକୁ ଫେରନ୍ତୁ"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"ପଛକୁ ଫେରିବା ପାଇଁ ଯେ କୌଣସି ସ୍ଥାନରେ ତିନି ଆଙ୍ଗୁଠି ବ୍ୟବହାର କରି ବାମ କିମ୍ବା ଡାହାଣକୁ ସ୍ୱାଇପ କରନ୍ତୁ।"</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"ଡାହାଣ ଏବଂ ବାମକୁ ତିନି ଆଙ୍ଗୁଠି ମୁଭ କରୁଥିବା ଟଚପେଡ ଦେଖାଉଛି"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 2e6c0da162be..3cb2e6dad5e4 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -103,8 +103,7 @@
<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>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"ਨੋਟ ਵਿੱਚ ਸ਼ਾਮਲ ਕਰੋ"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"ਲਿੰਕ ਸ਼ਾਮਲ ਕਰੋ"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"ਸਕ੍ਰੀਨ ਰਿਕਾਰਡਰ"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"ਸਕ੍ਰੀਨ ਰਿਕਾਰਡਿੰਗ ਜਾਰੀ ਹੈ"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"ਕਿਸੇ ਸਕ੍ਰੀਨ ਰਿਕਾਰਡ ਸੈਸ਼ਨ ਲਈ ਚੱਲ ਰਹੀ ਸੂਚਨਾ"</string>
@@ -196,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"ਚਿਹਰੇ ਰਾਹੀਂ ਅਣਲਾਕ ਕੀਤਾ ਗਿਆ। ਜਾਰੀ ਰੱਖਣ ਲਈ ਦਬਾਓ।"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"ਚਿਹਰੇ ਦੀ ਪਛਾਣ ਹੋਈ। ਜਾਰੀ ਰੱਖਣ ਲਈ ਦਬਾਓ।"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"ਚਿਹਰੇ ਦੀ ਪਛਾਣ ਹੋਈ। ਜਾਰੀ ਰੱਖਣ ਲਈ \'ਅਣਲਾਕ ਕਰੋ\' ਪ੍ਰਤੀਕ ਨੂੰ ਦਬਾਓ।"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"ਚਿਹਰੇ ਰਾਹੀਂ ਅਣਲਾਕ ਕੀਤਾ ਗਿਆ। ਜਾਰੀ ਰੱਖਣ ਲਈ ਟੈਪ ਕਰੋ।"</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"ਪ੍ਰਮਾਣਿਤ ਹੋਇਆ"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"ਪ੍ਰਮਾਣੀਕਰਨ ਰੱਦ ਕਰੋ"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"ਹੋਰ ਵਿਕਲਪ"</string>
@@ -478,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"ਹੋਰ ਵਿਜੇਟ ਸ਼ਾਮਲ ਕਰੋ"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"ਵਿਜੇਟਾਂ ਨੂੰ ਵਿਉਂਤਬੱਧ ਕਰਨ ਲਈ ਦਬਾਈ ਰੱਖੋ"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"ਵਿਜੇਟ ਵਿਉਂਤਬੱਧ ਕਰੋ"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"ਵਿਜੇਟਾਂ ਨੂੰ ਵਿਉਂਤਬੱਧ ਕਰਨ ਲਈ ਅਣਲਾਕ ਕਰੋ"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"ਬੰਦ ਵਿਜੇਟ ਲਈ ਐਪ ਪ੍ਰਤੀਕ"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"ਸਥਾਪਤ ਕੀਤੇ ਜਾ ਰਹੇ ਵਿਜੇਟ ਲਈ ਐਪ ਪ੍ਰਤੀਕ"</string>
<string name="edit_widget" msgid="9030848101135393954">"ਵਿਜੇਟ ਦਾ ਸੰਪਾਦਨ ਕਰੋ"</string>
@@ -1378,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"ਵਾਪਸ ਜਾਓ"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"ਵਾਪਸ ਜਾਣ ਲਈ, ਟੱਚਪੈਡ \'ਤੇ ਕਿਤੇ ਵੀ ਤਿੰਨ ਉਂਗਲਾਂ ਦੀ ਵਰਤੋਂ ਕਰ ਕੇ ਖੱਬੇ ਜਾਂ ਸੱਜੇ ਪਾਸੇ ਵੱਲ ਸਵਾਈਪ ਕਰੋ।"</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"ਟੱਚਪੈਡ \'ਤੇ ਤਿੰਨ ਉਂਗਲਾਂ ਨੂੰ ਸੱਜੇ ਅਤੇ ਖੱਬੇ ਪਾਸੇ ਵੱਲ ਲਿਜਾਂਦੇ ਹੋਏ ਦਿਖਾਇਆ ਜਾ ਰਿਹਾ ਹੈ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 464c7c8ad10d..b679e8200c67 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -476,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Dodaj więcej widżetów"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Przytrzymaj, aby dostosować widżety"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Dostosuj widżety"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"Odblokuj, aby dostosować widżety"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Ikona aplikacji z wyłączonym widżetem"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Ikona aplikacji instalowanego widżetu"</string>
<string name="edit_widget" msgid="9030848101135393954">"Edytuj widżet"</string>
@@ -1376,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Wróć"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"Aby wrócić, przesuń 3 palcami w lewo lub w prawo w dowolnym miejscu touchpada."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"3 palce na touchpadzie poruszające się w prawo i w lewo"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index e1f1050ea08d..29b845282f67 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -476,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Adicione mais widgets"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Mantenha pressionado para personalizar widgets"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Personalizar widgets"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"Desbloqueie para personalizar widgets"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Ícone do app para widget desativado"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Ícone do app para um widget que está sendo instalado"</string>
<string name="edit_widget" msgid="9030848101135393954">"Editar widget"</string>
@@ -1376,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Voltar"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"Para voltar, deslize para a esquerda ou direita usando 3 dedos em qualquer lugar do touchpad."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"Touchpad mostrando 3 dedos deslizando para a direita e esquerda"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index c8bba38ffdae..cdec12e1f649 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -476,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Adicionar mais widgets"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Mantenha pressionado para personalizar os widgets"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Personalizar widgets"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"Desbloqueie para personalizar widgets"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Ícone da app do widget desativado"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Ícone da app para um widget que está a ser instalado"</string>
<string name="edit_widget" msgid="9030848101135393954">"Editar widget"</string>
@@ -1376,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Voltar"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"Para retroceder, deslize rapidamente para a esquerda ou direita com três dedos em qualquer parte do touchpad."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"Touchpad a mostrar três dedos a moverem-se para a direita e esquerda"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index e1f1050ea08d..29b845282f67 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -476,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Adicione mais widgets"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Mantenha pressionado para personalizar widgets"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Personalizar widgets"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"Desbloqueie para personalizar widgets"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Ícone do app para widget desativado"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Ícone do app para um widget que está sendo instalado"</string>
<string name="edit_widget" msgid="9030848101135393954">"Editar widget"</string>
@@ -1376,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Voltar"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"Para voltar, deslize para a esquerda ou direita usando 3 dedos em qualquer lugar do touchpad."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"Touchpad mostrando 3 dedos deslizando para a direita e esquerda"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index ff4836e5452b..4da9b7099ab0 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -103,8 +103,7 @@
<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>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Adaugă în notă"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"Include linkul"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Recorder pentru ecran"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Se procesează înregistrarea"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notificare în curs pentru o sesiune de înregistrare a ecranului"</string>
@@ -196,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"S-a deblocat cu ajutorul feței. Apasă pentru a continua."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Chipul a fost recunoscut. Apasă pentru a continua."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Chip recunoscut. Apasă pictograma Deblocare ca să continui."</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"S-a deblocat folosind fața. Atinge pentru a continua."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autentificat"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"Anulează autentificarea"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"Mai multe opțiuni"</string>
@@ -478,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Adaugă mai multe widgeturi"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Apasă lung pentru a personaliza widgeturi"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Personalizează widgeturile"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"Deblochează ca să personalizezi widgeturi"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Pictograma aplicației pentru widgetul dezactivat"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Pictograma aplicației pentru un widget care se instalează"</string>
<string name="edit_widget" msgid="9030848101135393954">"Editează widgetul"</string>
@@ -1378,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Înapoi"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"Pentru a reveni, glisează spre stânga sau spre dreapta cu trei degete oriunde pe touchpad."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"Touchpad cu trei degete care se mișcă spre dreapta și spre stânga"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 3860d6fc5c8e..4e28df5b6e9f 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -103,8 +103,7 @@
<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>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Добавить в заметку"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"Добавить ссылку"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Запись видео с экрана"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Обработка записи с экрана…"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Текущее уведомление для записи видео с экрана"</string>
@@ -196,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Разблокировано сканированием лица. Нажмите, чтобы продолжить."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Лицо распознано. Нажмите, чтобы продолжить."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Лицо распознано. Нажмите на значок разблокировки."</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"Сканирование лица выполнено. Нажмите, чтобы продолжить."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Аутентификация выполнена"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"Отмена распознавания лица"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"Ещё"</string>
@@ -478,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Добавить виджеты"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Нажмите и удерживайте, чтобы настроить виджеты."</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Настроить виджеты"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"Чтобы настроить виджеты, разблокируйте устройство."</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Значок приложения для отключенного виджета"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Значок приложения для устанавливаемого виджета"</string>
<string name="edit_widget" msgid="9030848101135393954">"Изменить виджет"</string>
@@ -1378,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Назад"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"Чтобы вернуться, проведите тремя пальцами влево или вправо по сенсорной панели."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"Три пальца двигаются вправо и влево по сенсорной панели"</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 30a3b56349cb..bd9488db46f9 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -103,8 +103,7 @@
<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>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"සටහනට එක් කරන්න"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"සබැඳිය ඇතුළත් කරන්න"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"තිර රෙකෝඩරය"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"තිර පටිගත කිරීම සකසමින්"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"තිර පටිගත කිරීමේ සැසියක් සඳහා කෙරෙන දැනුම් දීම"</string>
@@ -196,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"මුහුණ මගින් අගුලු හරින ලදි. ඉදිරියට යාමට ඔබන්න."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"මුහුණ හඳුනා ගන්නා ලදි. ඉදිරියට යාමට ඔබන්න."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"මුහුණ හඳුනා ගන්නා ලදි. ඉදිරියට යාමට අගුලු හැරීමේ නිරූපකය ඔබන්න."</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"මුහුණ මගින් අගුළු හරින ලදි. ඉදිරියට යාමට තට්ටු කරන්න."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"සත්‍යාපනය විය"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"සත්‍යාපනය අවලංගු කරන්න"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"තවත් විකල්ප"</string>
@@ -478,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"තවත් විජට් එක් කරන්න"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"විජට් අභිරුචිකරණය කිරීමට දිගු ඔබන්න"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"විජට්ටු අභිරුචි කරන්න"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"විජට් අභිරුචිකරණය කිරීමට අගුළු හරින්න"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"අබල කළ විජට් සඳහා යෙදුම් නිරූපකය"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"විජට්ටුවක් සඳහා ස්ථාපන කරනු ලබන යෙදුම් නිරූපකය"</string>
<string name="edit_widget" msgid="9030848101135393954">"විජට්ටු සංස්කරණ කරන්න"</string>
@@ -1378,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"ආපස්සට යන්න"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"ආපසු යාමට, ස්පර්ශ පුවරුවේ ඕනෑම තැනක ඇඟිලි තුනක් භාවිතයෙන් වමට හෝ දකුණට ස්වයිප් කරන්න."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"ඇඟිලි තුනක් දකුණට සහ වමට චලනය වන බව පෙන්වන ස්පර්ශක පුවරුව"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index cf35af0cfbf8..796b2e13f687 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -103,8 +103,7 @@
<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>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Pridať do poznámky"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"Zahrnúť odkaz"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Rekordér obrazovky"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Spracúva sa záznam obrazovky"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Zobrazuje sa upozornenie týkajúce sa relácie záznamu obrazovky"</string>
@@ -196,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Odomknuté tvárou. Pokračujte stlačením."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Tvár bola rozpoznaná. Pokračujte stlačením."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Tvár bola rozpoznaná. Pokračujte stlačením ikony odomknutia"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"Odomknuté tvárou. Pokračujte klepnutím."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Overené"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"Zrušiť overenie"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"Ďalšie možnosti"</string>
@@ -478,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Pridať ďalšie miniaplikácie"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Miniaplikácie prispôsobíte dlhým stlačením"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Prispôsobiť miniaplikácie"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"Odomknite a prispôsobte si miniaplikácie"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Ikona deaktivovanej miniaplikácie"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Ikona inštalovanej miniaplikácie"</string>
<string name="edit_widget" msgid="9030848101135393954">"Upraviť miniaplikáciu"</string>
@@ -1378,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Prejsť späť"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"Ak chcete prejsť späť, potiahnite doľava alebo doprava troma prstami kdekoľvek na touchpade."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"Tri prsty na touchpade pohybujúce sa doprava a doľava"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index c493c5e036c9..2b8d8af4d3bf 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -103,8 +103,7 @@
<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>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Dodaj v zapisek"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"Vključi povezavo"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Snemalnik zaslona"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Obdelava videoposnetka zaslona"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Nenehno obveščanje o seji snemanja zaslona"</string>
@@ -196,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Odklenjeno z obrazom. Pritisnite za nadaljevanje."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Obraz je prepoznan. Pritisnite za nadaljevanje."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Obraz je prepoznan. Za nadaljevanje pritisnite ikono za odklepanje."</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"Odklenjeno z obrazom. Dotaknite se, če želite nadaljevati."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Preverjena pristnost"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"Prekliči preverjanje pristnosti"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"Več možnosti"</string>
@@ -478,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Dodajte več pripomočkov"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Pridržite za prilagajanje pripomočkov"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Prilagajanje pripomočkov"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"Odklenite, če želite prilagoditi pripomočke"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Ikona aplikacije za onemogočen pripomoček"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Ikona aplikacije za nameščanje pripomočka"</string>
<string name="edit_widget" msgid="9030848101135393954">"Urejanje pripomočka"</string>
@@ -1378,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Nazaj"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"Za pomik nazaj povlecite levo ali desno s tremi prsti kjer koli na sledilni ploščici."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"Sledilna ploščica s tremi prsti, ki se premikajo desno in levo"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index e189e9c82132..27d2c6c45dc1 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -103,8 +103,7 @@
<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>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Shto te shënimi"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"Përfshi lidhjen"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Regjistruesi i ekranit"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Regjistrimi i ekranit po përpunohet"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Njoftim i vazhdueshëm për një seancë regjistrimi të ekranit"</string>
@@ -134,8 +133,7 @@
<string name="screenrecord_stop_dialog_message_specific_app" msgid="5285148796772616326">"Do të ndalosh regjistrimin me &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;"</string>
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
- <!-- no translation found for share_to_app_chip_accessibility_label (4210256229976947065) -->
- <skip />
+ <string name="share_to_app_chip_accessibility_label" msgid="4210256229976947065">"Ekrani po ndahet"</string>
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
@@ -143,8 +141,7 @@
<string name="share_to_app_stop_dialog_message_specific_app" msgid="124371406810544777">"Do të ndalosh ndarjen e &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;"</string>
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
- <!-- no translation found for cast_to_other_device_chip_accessibility_label (1680650146639059938) -->
- <skip />
+ <string name="cast_to_other_device_chip_accessibility_label" msgid="1680650146639059938">"Po transmeton ekranin"</string>
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
@@ -198,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"U shkyç me fytyrë. Shtyp për të vazhduar."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Fytyra u njoh. Shtyp për të vazhduar."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Fytyra u njoh. Shtyp ikonën e shkyçjes për të vazhduar."</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"U shkyç me fytyrë. Trokit për të vazhduar."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"U vërtetua"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"Anulo vërtetimin"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"Opsione të tjera"</string>
@@ -480,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Shto miniaplikacione të tjera"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Shtyp gjatë për të personalizuar miniaplikacionet"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Personalizo miniaplikacionet"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"Shkyç për të personalizuar miniaplikacionet"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Ikona e aplikacionit për miniaplikacionin e çaktivizuar"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Ikona e aplikacionit për një miniaplikacion që po instalohet"</string>
<string name="edit_widget" msgid="9030848101135393954">"Modifiko miniaplikacionin"</string>
@@ -1359,15 +1354,11 @@
<string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"Në përdorim nga <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string>
<string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"Përdorur së fundi nga <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string>
<string name="shortcut_helper_category_system" msgid="462110876978937359">"Sistemi"</string>
- <!-- no translation found for shortcut_helper_category_system_controls (3153344561395751020) -->
- <skip />
- <!-- no translation found for shortcut_helper_category_system_apps (6001757545472556810) -->
- <skip />
+ <string name="shortcut_helper_category_system_controls" msgid="3153344561395751020">"Kontrollet e sistemit"</string>
+ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Aplikacionet e sistemit"</string>
<string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Kryerja e shumë detyrave"</string>
- <!-- no translation found for shortcutHelper_category_recent_apps (7918731953612377145) -->
- <skip />
- <!-- no translation found for shortcutHelper_category_split_screen (1159669813444812244) -->
- <skip />
+ <string name="shortcutHelper_category_recent_apps" msgid="7918731953612377145">"Aplikacionet e fundit"</string>
+ <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Ekrani i ndarë"</string>
<string name="shortcut_helper_category_input" msgid="8674018654124839566">"Hyrja"</string>
<string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Shkurtoret e aplikacionit"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Qasshmëria"</string>
@@ -1384,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Kthehu prapa"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"Për t\'u kthyer prapa, rrëshqit shpejt majtas ose djathtas duke përdorur tre gishta kudo në bllokun me prekje."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"Blloku me prekje që tregon tre gishta që lëvizin djathtas dhe majtas"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index aac4c0b32fce..a1ede045a42a 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -103,8 +103,7 @@
<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>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Додај у белешку"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"Уврсти линк"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Снимач екрана"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Обрађујемо видео снимка екрана"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Обавештење о сесији снимања екрана је активно"</string>
@@ -196,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Откључано је лицем. Притисните да бисте наставили."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Лице је препознато. Притисните да бисте наставили."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Лице препознато. Притисните икону откључавања за наставак."</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"Откључано је лицем. Додирните да бисте наставили."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Идентитет је потврђен"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"Откажите потврду идентитета"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"Још опција"</string>
@@ -478,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Додајте још виџета"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Дуги притисак за прилагођавање виџета"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Прилагоди виџете"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"Откључајте да бисте прилагодили виџете"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Икона апликације за онемогућен виџет"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Икона апликације за виџет који се инсталира"</string>
<string name="edit_widget" msgid="9030848101135393954">"Измени виџет"</string>
@@ -1378,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Назад"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"Да бисте се вратили, превуците улево или удесно са три прста било где на тачпеду."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"Тачпед са приказом три прста који се померају удесно и улево"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 39d81b9f8e5d..1824a4051bd9 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -103,8 +103,7 @@
<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>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Lägg till i anteckning"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"Inkludera länk"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Skärminspelare"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Behandlar skärminspelning"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Avisering om att skärminspelning pågår"</string>
@@ -196,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Upplåst med ansiktslås. Tryck för att fortsätta."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Ansiktet har identifierats. Tryck för att fortsätta."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Ansiktet har identifierats. Tryck på ikonen lås upp."</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"Upplåst med ansiktslås. Tryck för att fortsätta."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autentiserad"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"Avbryt autentiseringen"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"Fler alternativ"</string>
@@ -478,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Lägg till fler widgetar"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Tryck länge för att anpassa widgetar"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Anpassa widgetar"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"Lås upp för att anpassa widgetar"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Appikon för inaktiverad widget"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Appikon för en widget som installeras"</string>
<string name="edit_widget" msgid="9030848101135393954">"Redigera widget"</string>
@@ -1378,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Tillbaka"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"Gå tillbaka genom att svepa åt vänster eller höger med tre fingrar var som helst på styrplattan."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"Tre fingrar rör sig åt höger och vänster på en styrplatta"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 253acf062b3f..a01dd71240d8 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -103,8 +103,7 @@
<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>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Ongeza kwenye dokezo"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"Jumuisha kiungo"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Kinasa Skrini"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Inachakata rekodi ya skrini"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Arifa inayoendelea ya kipindi cha kurekodi skrini"</string>
@@ -196,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Imefunguliwa kwa kutumia uso wako. Bonyeza ili uendelee."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Uso umetambuliwa. Bonyeza ili uendelee."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Uso umetambuliwa. Bonyeza aikoni ya kufungua ili uendelee."</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"Imefunguliwa kwa kutumia uso wako. Gusa ili uendelee."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Umethibitishwa"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"Ghairi Uthibitishaji"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"Chaguo Zaidi"</string>
@@ -478,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Weka wijeti zingine"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Bonyeza kwa muda mrefu uweke mapendeleo ya wijeti"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Badilisha wijeti upendavyo"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"Fungua ili ubadilishe wijeti upendavyo"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Aikoni ya programu ya wijeti iliyozimwa"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Aikoni ya programu ya wijeti inayowekwa"</string>
<string name="edit_widget" msgid="9030848101135393954">"Badilisha wijeti"</string>
@@ -1378,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Rudi nyuma"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"Ili kurudi nyuma, telezesha vidole vitatu kushoto au kulia mahali popote kwenye padi ya kugusa."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"Padi ya kugusa inayoonyesha vidole vitatu vikisonga kulia na kushoto"</string>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 159c4c570bf5..93e47ffe3e1c 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -103,8 +103,7 @@
<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>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"குறிப்பில் சேர்"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"இணைப்பைச் சேர்"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"ஸ்கிரீன் ரெக்கார்டர்"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"ஸ்க்ரீன் ரெக்கார்டிங் செயலாக்கப்படுகிறது"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"திரை ரெக்கார்டிங் அமர்விற்கான தொடர் அறிவிப்பு"</string>
@@ -196,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"முகம் மூலம் அன்லாக் செய்யப்பட்டது. தொடர அழுத்தவும்."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"முகம் அங்கீகரிக்கப்பட்டது. தொடர அழுத்தவும்."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"முகம் அங்கீகரிக்கப்பட்டது. தொடர அன்லாக் ஐகானை அழுத்தவும்."</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"முகம் கொண்டு அன்லாக் செய்யப்பட்டது. தொடர தட்டவும்."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"அங்கீகரிக்கப்பட்டது"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"அங்கீகரிப்பை ரத்துசெய்"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"கூடுதல் விருப்பங்கள்"</string>
@@ -478,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"கூடுதல் விட்ஜெட்களைச் சேருங்கள்"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"விட்ஜெட்களைப் பிரத்தியேகமாக்க நீண்ட நேரம் அழுத்துக"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"விட்ஜெட்களைப் பிரத்தியேகமாக்குங்கள்"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"விட்ஜெட்களைப் பிரத்தியேகப்படுத்த அன்லாக் செய்யுங்கள்"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"முடக்கப்பட்ட விட்ஜெட்டுக்கான ஆப்ஸ் ஐகான்"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"நிறுவப்படும் விட்ஜெட்டுக்கான ஆப்ஸ் ஐகான்"</string>
<string name="edit_widget" msgid="9030848101135393954">"விட்ஜெட்டைத் திருத்து"</string>
@@ -1378,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"பின்செல்"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"பின்செல்ல, உங்கள் டச்பேடில் எங்கு வேண்டுமானாலும் இடது அல்லது வலதுபுறமாக மூன்று விரல்களால் ஸ்வைப் செய்யவும்."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"மூன்று விரல்கள் வலது மற்றும் இடதுபுறம் நகர்வதை டச்பேட் காட்டுகிறது"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 6a91bca56717..759b6cae56d3 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -476,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"మరిన్ని విడ్జెట్‌లను జోడించండి"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"విడ్జెట్‌లను అనుకూలీకరించడానికి, నొక్కి, ఉంచండి"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"విడ్జెట్‌లను అనుకూలంగా మార్చండి"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"విడ్జెట్‌లను అనుకూలంగా మార్చుకోవడానికి అన్‌లాక్ చేయండి"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"డిజేబుల్ చేయబడిన విడ్జెట్ కోసం యాప్ చిహ్నం"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"ఇన్‌స్టాల్ చేస్తున్న విడ్జెట్ కోసం యాప్ చిహ్నం"</string>
<string name="edit_widget" msgid="9030848101135393954">"విడ్జెట్‌ను ఎడిట్ చేయండి"</string>
@@ -1376,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"వెనుకకు"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"వెనుకకు వెళ్లడానికి, టచ్‌ప్యాడ్‌లో ఎక్కడైనా మూడు వేళ్లను ఉపయోగించి ఎడమ లేదా కుడికి స్వైప్ చేయండి."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"మూడు వేళ్లు కుడి, ఎడమకు కదులుతున్నట్లు చూపే టచ్‌ప్యాడ్"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index c868b66718e5..4ed8a03bf423 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -103,8 +103,7 @@
<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>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"เพิ่มลงในโน้ต"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"รวมลิงก์"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"โปรแกรมบันทึกหน้าจอ"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"กำลังประมวลผลการอัดหน้าจอ"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"การแจ้งเตือนต่อเนื่องสำหรับเซสชันการบันทึกหน้าจอ"</string>
@@ -196,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"ปลดล็อกด้วยใบหน้าแล้ว กดเพื่อดำเนินการต่อ"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"จดจำใบหน้าได้ กดเพื่อดำเนินการต่อ"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"จดจำใบหน้าได้ กดไอคอนปลดล็อกเพื่อดำเนินการต่อ"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"ปลดล็อกด้วยใบหน้าแล้ว แตะเพื่อดำเนินการต่อ"</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"ตรวจสอบสิทธิ์แล้ว"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"ยกเลิกการตรวจสอบสิทธิ์"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"ตัวเลือกเพิ่มเติม"</string>
@@ -478,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"เพิ่มวิดเจ็ตอีก"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"กดค้างเพื่อปรับแต่งวิดเจ็ต"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"ปรับแต่งวิดเจ็ต"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"ปลดล็อกเพื่อปรับแต่งวิดเจ็ต"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"ไอคอนแอปสำหรับวิดเจ็ตที่ปิดใช้อยู่"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"ไอคอนแอปสำหรับวิดเจ็ตที่กำลังติดตั้ง"</string>
<string name="edit_widget" msgid="9030848101135393954">"แก้ไขวิดเจ็ต"</string>
@@ -1378,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"ย้อนกลับ"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"หากต้องการย้อนกลับ ให้ใช้ 3 นิ้วปัดไปทางซ้ายหรือขวาที่ใดก็ได้บนทัชแพด"</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"ทัชแพดแสดงภาพ 3 นิ้วเลื่อนไปทางขวาและซ้าย"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 005211d6a6ce..421283c5732a 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -103,8 +103,7 @@
<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>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Idagdag sa tala"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"Isama ang link"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Recorder ng Screen"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Pinoproseso screen recording"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Kasalukuyang notification para sa session ng pag-record ng screen"</string>
@@ -196,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Na-unlock gamit ang mukha. Pindutin para magpatuloy."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Nakilala ang mukha. Pindutin para magpatuloy."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Nakilala ang mukha. Pindutin ang unlock para magpatuloy."</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"Na-unlock gamit ang mukha. I-tap para magpatuloy."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Na-authenticate"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"Kanselahin ang Pag-authenticate"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"Higit Pang Opsyon"</string>
@@ -478,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Magdagdag ng higit pang widget"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Pindutin nang matagal para i-customize ang mga widget"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"I-customize ang mga widget"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"Mag-unlock para ma-customize ang mga widget"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Icon ng app para sa na-disable na widget"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Ini-install ang icon ng app para sa isang widget"</string>
<string name="edit_widget" msgid="9030848101135393954">"I-edit ang widget"</string>
@@ -1378,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Bumalik"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"Para bumalik, mag-swipe pakaliwa o pakanan gamit ang tatlong daliri kahit saan sa touchpad."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"Touchpad na nagpapakita ng tatlong daliring gumagalaw pakanan at pakaliwa"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index f468d5daf95b..8ad6deea1ea8 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -103,8 +103,7 @@
<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>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Nota ekle"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"Bağlantıyı dahil et"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Ekran Kaydedicisi"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Ekran kaydı işleniyor"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Ekran kaydı oturumu için devam eden bildirim"</string>
@@ -196,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Cihazın kilidini yüzünüzle açtınız. Devam etmek için basın."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Yüzünüz tanındı. Devam etmek için basın."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Yüzünüz tanındı. Kilit açma simgesine basın."</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"Kilidi yüzünüzle açtınız. Devam etmek için dokunun."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Kimliği Doğrulandı"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"Kimlik doğrulamayı iptal et"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"Diğer Seçenekler"</string>
@@ -478,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Daha fazla widget ekle"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Widget\'ları özelleştirmek için uzun basın"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Widget\'ları özelleştir"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"Widget\'ları özelleştirmek için kilidi açın"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Devre dışı bırakılan widget\'ın uygulama simgesi"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Yüklenmeye devam eden bir widget\'ın uygulama simgesi"</string>
<string name="edit_widget" msgid="9030848101135393954">"Widget\'ı düzenle"</string>
@@ -1378,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Geri dön"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"Geri dönmek için dokunmatik alanın herhangi bir yerinde üç parmağınızla sola veya sağa kaydırın."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"Sağa ve sola hareket eden üç parmağın gösterildiği dokunmatik alan"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index c13aac71e9ba..17931cff46c6 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -103,8 +103,7 @@
<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>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Додати до примітки"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"Додати посилання"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Запис відео з екрана"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Обробка записування екрана"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Сповіщення про сеанс запису екрана"</string>
@@ -134,8 +133,7 @@
<string name="screenrecord_stop_dialog_message_specific_app" msgid="5285148796772616326">"Ви зупините запис контенту з додатка &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;"</string>
<!-- no translation found for screenrecord_stop_dialog_button (2883812564938194350) -->
<skip />
- <!-- no translation found for share_to_app_chip_accessibility_label (4210256229976947065) -->
- <skip />
+ <string name="share_to_app_chip_accessibility_label" msgid="4210256229976947065">"Показ екрана"</string>
<!-- no translation found for share_to_app_stop_dialog_title (9212915050910250438) -->
<skip />
<!-- no translation found for share_to_app_stop_dialog_message (3181723638915877339) -->
@@ -143,8 +141,7 @@
<string name="share_to_app_stop_dialog_message_specific_app" msgid="124371406810544777">"Ви зупините надсилання контенту з додатка &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;"</string>
<!-- no translation found for share_to_app_stop_dialog_button (6334056916284230217) -->
<skip />
- <!-- no translation found for cast_to_other_device_chip_accessibility_label (1680650146639059938) -->
- <skip />
+ <string name="cast_to_other_device_chip_accessibility_label" msgid="1680650146639059938">"Трансляція екрана"</string>
<!-- no translation found for cast_to_other_device_stop_dialog_title (1910372600290258193) -->
<skip />
<!-- no translation found for cast_to_other_device_stop_dialog_message (1502520537030715412) -->
@@ -198,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Розблоковано (фейс-контроль). Натисніть, щоб продовжити."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Обличчя розпізнано. Натисніть, щоб продовжити."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Обличчя розпізнано. Натисніть значок розблокування."</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"Розблоковано (фейс-контроль). Натисніть, щоб продовжити."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Автентифіковано"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"Скасувати автентифікацію"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"Інші опції"</string>
@@ -480,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Додати більше віджетів"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Утримуйте, щоб налаштувати віджети"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Налаштувати віджети"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"Розблокуйте екран, щоб налаштувати віджети"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Значок додатка для вимкненого віджета"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Значок додатка для віджета, що встановлюється"</string>
<string name="edit_widget" msgid="9030848101135393954">"Редагувати віджет"</string>
@@ -1359,15 +1354,11 @@
<string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"Використовується додатком <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string>
<string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"Нещодавно використано (<xliff:g id="APP_NAME">%1$s</xliff:g>, <xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string>
<string name="shortcut_helper_category_system" msgid="462110876978937359">"Система"</string>
- <!-- no translation found for shortcut_helper_category_system_controls (3153344561395751020) -->
- <skip />
- <!-- no translation found for shortcut_helper_category_system_apps (6001757545472556810) -->
- <skip />
+ <string name="shortcut_helper_category_system_controls" msgid="3153344561395751020">"Елементи керування системою"</string>
+ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Системні додатки"</string>
<string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Багатозадачність"</string>
- <!-- no translation found for shortcutHelper_category_recent_apps (7918731953612377145) -->
- <skip />
- <!-- no translation found for shortcutHelper_category_split_screen (1159669813444812244) -->
- <skip />
+ <string name="shortcutHelper_category_recent_apps" msgid="7918731953612377145">"Нещодавні додатки"</string>
+ <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Розділити екран"</string>
<string name="shortcut_helper_category_input" msgid="8674018654124839566">"Введення"</string>
<string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Комбінації клавіш для додатків"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Доступність"</string>
@@ -1384,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Назад"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"Щоб перейти назад, проведіть трьома пальцями вліво або вправо по сенсорній панелі."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"Сенсорна панель із зображенням трьох пальців, що рухаються вправо й уліво"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 9c6df9036663..d597d4944ccf 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -103,8 +103,7 @@
<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>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"نوٹ میں شامل کریں"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"لنک شامل کریں"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"اسکرین ریکارڈر"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"سکرین ریکارڈنگ پروسیس ہورہی ہے"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"اسکرین ریکارڈ سیشن کیلئے جاری اطلاع"</string>
@@ -196,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"چہرے سے انلاک کیا گیا۔ جاری رکھنے کے لیے دبائیں۔"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"چہرے کی شناخت ہو گئی۔ جاری رکھنے کے لیے دبائیں۔"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"چہرے کی شناخت ہو گئی۔ جاری رکھنے کیلئے انلاک آئیکن دبائیں۔"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"چہرے سے غیر مقفل کیا گیا۔ جاری رکھنے کیلئے تھپتھپائیں۔"</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"تصدیق کردہ"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"تصدیق کو منسوخ کریں"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"مزید اختیارات"</string>
@@ -478,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"مزید ویجٹس شامل کریں"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"ویجٹس کو حسب ضرورت بنانے کے لیے لانگ پریس کریں"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"ویجیٹس کو حسب ضرورت بنائیں"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"ویجیٹس کو حسب ضرورت بنانے کے لیے غیر مقفل کریں"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"غیر فعال ویجیٹ کے لئے ایپ آئیکن"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"انسٹال ہونے والے ویجیٹ کا ایپ آئیکن"</string>
<string name="edit_widget" msgid="9030848101135393954">"ویجیٹ میں ترمیم کریں"</string>
@@ -1382,6 +1379,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"واپس جائیں"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"واپس جانے کے لیے، ٹچ پیڈ پر کہیں بھی تین انگلیوں کی مدد سے دائیں یا بائیں سوائپ کریں۔"</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"ٹچ پیڈ دائیں اور بائیں حرکت کرتی ہوئی تین انگلیاں دکھا رہا ہے"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 1e55f29f37f1..6ef40260af29 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -476,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Koʻproq vidjetlar qoʻshish"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Vidjetlarni sozlash uchun bosib turing"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Vidjetlarni moslashtirish"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"Vidjetlarni moslash uchun qulfdan chiqaring"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Faolsizlantirilgan vidjet uchun ilova belgisi"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Oʻrnatilayotgan vidjet uchun ilova belgisi"</string>
<string name="edit_widget" msgid="9030848101135393954">"Vidjetni tahrirlash"</string>
@@ -1376,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Orqaga qaytish"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"Ortga qaytish uchun sensorli panelda uchta barmoqni chapga yoki oʻngga suring."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"Sensorli panelda uchta barmoq chapga va oʻngga harakatlanishi"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index f52b83157bdb..88fe43667b62 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -103,8 +103,7 @@
<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>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Thêm vào ghi chú"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"Thêm đường liên kết"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Trình ghi màn hình"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Đang xử lý video ghi màn hình"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Thông báo đang diễn ra về phiên ghi màn hình"</string>
@@ -196,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Đã mở khoá bằng khuôn mặt. Hãy nhấn để tiếp tục."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Đã nhận diện khuôn mặt. Hãy nhấn để tiếp tục."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Đã nhận diện khuôn mặt. Nhấn biểu tượng mở khoá để tiếp tục."</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"Đã mở khoá bằng khuôn mặt. Nhấn để tiếp tục."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Đã xác thực"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"Huỷ quy trình xác thực"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"Tuỳ chọn khác"</string>
@@ -478,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Thêm tiện ích khác"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Nhấn và giữ để tuỳ chỉnh tiện ích"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Tuỳ chỉnh tiện ích"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"Mở khoá để tuỳ chỉnh các tiện ích"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Biểu tượng ứng dụng của tiện ích đã bị vô hiệu hoá"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Đang cài đặt biểu tượng ứng dụng của một tiện ích"</string>
<string name="edit_widget" msgid="9030848101135393954">"Chỉnh sửa tiện ích"</string>
@@ -1378,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Quay lại"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"Để quay lại, hãy vuốt sang trái hoặc sang phải bằng 3 ngón tay ở vị trí bất kỳ trên bàn di chuột."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"Minh hoạ thao tác di chuyển sang phải và sang trái bằng 3 ngón tay trên bàn di chuột"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 6a5d4be23ec8..3a89e353dde7 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -103,8 +103,7 @@
<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>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"添加到备注中"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"包括链接"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"屏幕录制器"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"正在处理屏幕录制视频"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"持续显示屏幕录制会话通知"</string>
@@ -196,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"已通过面孔识别解锁。点按即可继续。"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"识别出面孔。点按即可继续。"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"识别出面孔。按下解锁图标即可继续。"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"已通过面孔识别解锁。点按即可继续。"</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"已经过身份验证"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"取消身份验证"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"更多选项"</string>
@@ -478,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"添加更多微件"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"长按即可自定义微件"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"自定义微件"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"解锁即可自定义微件"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"已停用微件的应用图标"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"代表正在安装的微件的应用图标"</string>
<string name="edit_widget" msgid="9030848101135393954">"修改微件"</string>
@@ -1378,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"返回"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"如要返回,请使用三根手指在触控板上的任意位置左滑或右滑。"</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"触控板,其中显示了三根手指右移和左移"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 1e316e7822b4..1603b9bd78ec 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -476,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"新增更多小工具"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"長按即可自訂小工具"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"自訂小工具"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"解鎖即可自訂小工具"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"已停用小工具的應用程式圖示"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"此應用程式圖示用來表示安裝中的小工具"</string>
<string name="edit_widget" msgid="9030848101135393954">"編輯小工具"</string>
@@ -1376,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"返回"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"用三隻手指在觸控板上任何一處左右滑動即可返回。"</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"觸控板上有三隻手指左右移動"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index fa1136f1e759..3a1d369db3db 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -103,8 +103,7 @@
<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>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"新增至記事本"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"包含連結"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"螢幕錄影器"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"處理螢幕錄影內容"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"持續顯示螢幕畫面錄製工作階段通知"</string>
@@ -196,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"裝置已透過你的臉解鎖,按下即可繼續操作。"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"臉孔辨識完成,按下即可繼續操作。"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"臉孔辨識完成,按下「解鎖」圖示即可繼續操作。"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"裝置已透過你的臉解鎖,輕觸這裡即可繼續。"</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"已通過驗證"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"取消驗證"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"更多選項"</string>
@@ -478,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"新增更多小工具"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"長按即可自訂小工具"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"自訂小工具"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"解鎖即可自訂小工具"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"所停用小工具的應用程式圖示"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"這個應用程式圖示用來表示安裝中的小工具"</string>
<string name="edit_widget" msgid="9030848101135393954">"編輯小工具"</string>
@@ -1378,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"返回"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"如要返回,請用三指在觸控板上向左或右滑動。"</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"動畫顯示三指正在觸控板上向左右移動"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index e9e723966372..7aa428810200 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -103,8 +103,7 @@
<string name="screenshot_detected_template" msgid="7940376642921719915">"I-<xliff:g id="APPNAME">%1$s</xliff:g> ithole lesi sithombe-skrini."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"I-<xliff:g id="APPNAME">%1$s</xliff:g> namanye ama-app avuliwe athole lesi sithombe-skrini."</string>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Engeza kunothi"</string>
- <!-- no translation found for backlinks_include_link (4562093591148248158) -->
- <skip />
+ <string name="backlinks_include_link" msgid="4562093591148248158">"Faka ilinki"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Okokuqopha iskrini"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Icubungula okokuqopha iskrini"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Isaziso esiqhubekayo seseshini yokurekhoda isikrini"</string>
@@ -196,8 +195,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Vula ngobuso. Cindezela ukuze uqhubeke."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Ubuso buyaziwa. Cindezela ukuze uqhubeke."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Ubuso buyaziwa. Cindezela isithonjana sokuvula ukuze uqhubeke."</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face_sfps (2499213248903257928) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"Kuvulwe ngobuso. Thepha ukuze uqhubeke."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Kugunyaziwe"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"Khansela Ukuqinisekisa"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"Okukhethwayo Okwengeziwe"</string>
@@ -478,8 +476,7 @@
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Engeza amawijethi engeziwe"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Cindezela isikhathi eside ukuze wenze ngokwezifiso amawijethi"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Yenza ngokwezifiso amawijethi"</string>
- <!-- no translation found for unlock_reason_to_customize_widgets (5011909432460546033) -->
- <skip />
+ <string name="unlock_reason_to_customize_widgets" msgid="5011909432460546033">"Vula ukuze uhlele amawijethi ngendlela oyifisayo"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Isithonjana se-app sewijethi evaliwe"</string>
<string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Isithonjana se-app sewijethi siyafakwa"</string>
<string name="edit_widget" msgid="9030848101135393954">"Hlela amawijethi"</string>
@@ -1378,6 +1375,8 @@
<skip />
<!-- no translation found for touchpad_tutorial_done_button (176168488821755503) -->
<skip />
+ <!-- no translation found for touchpad_tutorial_gesture_done (4784438360736821255) -->
+ <skip />
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Buyela emuva"</string>
<string name="touchpad_back_gesture_guidance" msgid="4222430588599527272">"Ukuze ubuyele emuva, swayiphela kwesokunxele noma kwesokudla usebenzisa iminwe emithathu noma yikuphi ephedini yokuthinta."</string>
<string name="touchpad_back_gesture_animation_content_description" msgid="2646107450922379918">"Iphedi yokuthinta ebonisa iminwe emithathu iya kwesokudla nakwesokunxele"</string>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index ca55c2394203..0350cd7dab98 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -100,8 +100,8 @@
<!-- The color of the navigation bar icons. Need to be in sync with ic_sysbar_* -->
<color name="navigation_bar_icon_color">#E5FFFFFF</color>
- <color name="white">@*android:color/white</color>
- <color name="black">@*android:color/black</color>
+ <color name="navigation_bar_home_handle_light_color">#EBffffff</color>
+ <color name="navigation_bar_home_handle_dark_color">#99000000</color>
<!-- The shadow color for light navigation bar icons. -->
<color name="nav_key_button_shadow_color">#30000000</color>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 84d5dcbae253..7f7e6347b2f7 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -56,7 +56,7 @@
enabled for OLED devices to reduce/prevent burn in on the navigation bar (because of the
black background and static button placements) and disabled for all other devices to
prevent wasting cpu cycles on the dimming animation -->
- <bool name="config_navigation_bar_enable_auto_dim_no_visible_wallpaper">false</bool>
+ <bool name="config_navigation_bar_enable_auto_dim_no_visible_wallpaper">true</bool>
<!-- The maximum number of tiles in the QuickQSPanel -->
<integer name="quick_qs_panel_max_tiles">4</integer>
@@ -104,7 +104,7 @@
<!-- Tiles native to System UI. Order should match "quick_settings_tiles_default" -->
<string name="quick_settings_tiles_stock" translatable="false">
- internet,bt,flashlight,dnd,alarm,airplane,controls,wallet,rotation,battery,cast,screenrecord,mictoggle,cameratoggle,location,hotspot,inversion,saver,dark,work,night,reverse,reduce_brightness,qr_code_scanner,onehanded,color_correction,dream,font_scaling,record_issue,hearing_devices
+ internet,bt,flashlight,dnd,modes,alarm,airplane,controls,wallet,rotation,battery,cast,screenrecord,mictoggle,cameratoggle,location,hotspot,inversion,saver,dark,work,night,reverse,reduce_brightness,qr_code_scanner,onehanded,color_correction,dream,font_scaling,record_issue,hearing_devices
</string>
<!-- The tiles to display in QuickSettings -->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 40bdc3eb50f8..eda7bb0e7f6d 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1323,6 +1323,7 @@
<dimen name="magnifier_drag_handle_padding">3dp</dimen>
<!-- Magnification settings panel -->
<dimen name="magnification_setting_view_margin">24dp</dimen>
+ <dimen name="magnification_setting_view_item_horizontal_spacing">12dp</dimen>
<dimen name="magnification_setting_text_size">18sp</dimen>
<dimen name="magnification_setting_background_padding">24dp</dimen>
<dimen name="magnification_setting_background_corner_radius">28dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index dee55289958e..2bd97d9a2f91 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -716,6 +716,8 @@
<!-- QuickSettings: Do not disturb - Priority only [CHAR LIMIT=NONE] -->
<!-- QuickSettings: Do not disturb - Alarms only [CHAR LIMIT=NONE] -->
<!-- QuickSettings: Do not disturb - Total silence [CHAR LIMIT=NONE] -->
+ <!-- QuickSettings: Priority modes [CHAR LIMIT=NONE] -->
+ <string name="quick_settings_modes_label">Priority modes</string>
<!-- QuickSettings: Bluetooth [CHAR LIMIT=NONE] -->
<string name="quick_settings_bluetooth_label">Bluetooth</string>
<!-- QuickSettings: Bluetooth (Multiple) [CHAR LIMIT=NONE] -->
@@ -1871,7 +1873,7 @@
<string name="notification_channel_summary_low">No sound or vibration</string>
<!-- [CHAR LIMIT=150] Notification Importance title: low importance level summary -->
- <string name="notification_conversation_summary_low">No sound or vibration and appears lower in conversation section</string>
+ <string name="notification_conversation_summary_low">No sound or vibration but still appears in the conversation section</string>
<!-- [CHAR LIMIT=150] Notification Importance title: normal importance level summary -->
<string name="notification_channel_summary_default">May ring or vibrate based on device settings</string>
@@ -2050,6 +2052,8 @@
<string name="keyboard_key_page_down">Page Down</string>
<!-- Name used to refer to the "Delete" key on the keyboard. -->
<string name="keyboard_key_forward_del">Delete</string>
+ <!-- Name used to refer to the "Esc" or "Escape" key on the keyboard. -->
+ <string name="keyboard_key_esc">Esc</string>
<!-- Name used to refer to the "Home" move key on the keyboard. -->
<string name="keyboard_key_move_home">Home</string>
<!-- Name used to refer to the "End" move key on the keyboard. -->
@@ -3595,6 +3599,10 @@
that shows the user which keyboard shortcuts they can use. The "App shortcuts" are
for example "Open browser" or "Open calculator". [CHAR LIMIT=NONE] -->
<string name="shortcut_helper_category_app_shortcuts">App shortcuts</string>
+ <!-- Default Title of the keyboard shortcut helper category for current app. The helper is a
+ component that shows the user which keyboard shortcuts they can use. The current app
+ shortcuts are shortcuts provided by the currently open app. [CHAR LIMIT=NONE] -->
+ <string name="shortcut_helper_category_current_app_shortcuts">Current App</string>
<!-- Title of the keyboard shortcut helper category "Accessibility". The helper is a component
that shows the user which keyboard shortcuts they can use. The "Accessibility" shortcuts
are for example "Turn on talkback". [CHAR LIMIT=NONE] -->
@@ -3650,4 +3658,6 @@
<string name="home_controls_dream_label">Home Controls</string>
<!-- Description for home control panel [CHAR LIMIT=67] -->
<string name="home_controls_dream_description">Quickly access your home controls as a screensaver</string>
+ <!-- Label for volume undo action [CHAR LIMIT=NONE] -->
+ <string name="volume_undo_action">Undo</string>
</resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 047578c43159..36912acbbdb9 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -622,14 +622,14 @@
<style name="DualToneLightTheme">
<item name="iconBackgroundColor">@color/light_mode_icon_color_dual_tone_background</item>
<item name="fillColor">@color/light_mode_icon_color_dual_tone_fill</item>
- <item name="singleToneColor">@color/white</item>
- <item name="homeHandleColor">@color/white</item>
+ <item name="singleToneColor">@color/light_mode_icon_color_single_tone</item>
+ <item name="homeHandleColor">@color/navigation_bar_home_handle_light_color</item>
</style>
<style name="DualToneDarkTheme">
<item name="iconBackgroundColor">@color/dark_mode_icon_color_dual_tone_background</item>
<item name="fillColor">@color/dark_mode_icon_color_dual_tone_fill</item>
- <item name="singleToneColor">@color/black</item>
- <item name="homeHandleColor">@color/black</item>
+ <item name="singleToneColor">@color/dark_mode_icon_color_single_tone</item>
+ <item name="homeHandleColor">@color/navigation_bar_home_handle_dark_color</item>
</style>
<style name="QSHeaderDarkTheme">
<item name="iconBackgroundColor">@color/dark_mode_qs_icon_color_dual_tone_background</item>
@@ -648,7 +648,7 @@
<item name="singleToneColor">?android:attr/textColorPrimary</item>
</style>
<style name="ScreenPinningRequestTheme" parent="@*android:style/ThemeOverlay.DeviceDefault.Accent">
- <item name="singleToneColor">@color/white</item>
+ <item name="singleToneColor">@color/light_mode_icon_color_single_tone</item>
</style>
<style name="TextAppearance.Volume">
@@ -1604,7 +1604,6 @@
<item name="android:fontFamily">google-sans</item>
<item name="android:textColor">?androidprv:attr/textColorPrimary</item>
<item name="android:textSize">@dimen/magnification_setting_text_size</item>
- <item name="android:singleLine">true</item>
</style>
<style name="TextAppearance.MagnificationSetting.EditButton">
diff --git a/packages/SystemUI/res/values/tiles_states_strings.xml b/packages/SystemUI/res/values/tiles_states_strings.xml
index ad09b466dd3e..c7029272db7d 100644
--- a/packages/SystemUI/res/values/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values/tiles_states_strings.xml
@@ -85,6 +85,16 @@
<item>On</item>
</string-array>
+ <!-- State names for modes (Priority modes) tile: unavailable, off, on.
+ This subtitle is shown when the tile is in that particular state but does not set its own
+ subtitle, so some of these may never appear on screen. They should still be translated as
+ if they could appear. [CHAR LIMIT=32] -->
+ <string-array name="tile_states_modes">
+ <item>Unavailable</item>
+ <item>Off</item>
+ <item>On</item>
+ </string-array>
+
<!-- State names for flashlight tile: unavailable, off, on.
This subtitle is shown when the tile is in that particular state but does not set its own
subtitle, so some of these may never appear on screen. They should still be translated as
diff --git a/packages/SystemUI/res/xml/large_screen_shade_header.xml b/packages/SystemUI/res/xml/large_screen_shade_header.xml
index fe61c46e341d..eb0aae9ebcf1 100644
--- a/packages/SystemUI/res/xml/large_screen_shade_header.xml
+++ b/packages/SystemUI/res/xml/large_screen_shade_header.xml
@@ -33,6 +33,7 @@
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_marginStart="8dp"
+ app:layout_constraintBaseline_toBaselineOf="@id/clock"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/clock"
app:layout_constraintTop_toTopOf="parent" />
diff --git a/packages/SystemUI/schemas/com.android.systemui.communal.data.db.CommunalDatabase/2.json b/packages/SystemUI/schemas/com.android.systemui.communal.data.db.CommunalDatabase/2.json
new file mode 100644
index 000000000000..f10d92a3fc0f
--- /dev/null
+++ b/packages/SystemUI/schemas/com.android.systemui.communal.data.db.CommunalDatabase/2.json
@@ -0,0 +1,81 @@
+{
+ "formatVersion": 1,
+ "database": {
+ "version": 2,
+ "identityHash": "02e2da2d36e6955200edd5fb49e63c72",
+ "entities": [
+ {
+ "tableName": "communal_widget_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uid` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `widget_id` INTEGER NOT NULL, `component_name` TEXT NOT NULL, `item_id` INTEGER NOT NULL, `user_serial_number` INTEGER NOT NULL DEFAULT -1)",
+ "fields": [
+ {
+ "fieldPath": "uid",
+ "columnName": "uid",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "widgetId",
+ "columnName": "widget_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "componentName",
+ "columnName": "component_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "itemId",
+ "columnName": "item_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userSerialNumber",
+ "columnName": "user_serial_number",
+ "affinity": "INTEGER",
+ "notNull": true,
+ "defaultValue": "-1"
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "uid"
+ ]
+ }
+ },
+ {
+ "tableName": "communal_item_rank_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uid` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `rank` INTEGER NOT NULL DEFAULT 0)",
+ "fields": [
+ {
+ "fieldPath": "uid",
+ "columnName": "uid",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "rank",
+ "columnName": "rank",
+ "affinity": "INTEGER",
+ "notNull": true,
+ "defaultValue": "0"
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "uid"
+ ]
+ }
+ }
+ ],
+ "setupQueries": [
+ "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
+ "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '02e2da2d36e6955200edd5fb49e63c72')"
+ ]
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index a42f4c2dda4c..baf8f5aeba29 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -54,7 +54,6 @@ import com.android.systemui.statusbar.phone.SystemUIDialogManager;
import com.android.systemui.statusbar.policy.BluetoothController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.window.StatusBarWindowController;
-import com.android.systemui.tuner.TunablePadding.TunablePaddingService;
import com.android.systemui.tuner.TunerService;
import dagger.Lazy;
@@ -129,7 +128,6 @@ public class Dependency {
@Nullable
@Inject Lazy<VolumeDialogController> mVolumeDialogController;
@Inject Lazy<MetricsLogger> mMetricsLogger;
- @Inject Lazy<TunablePaddingService> mTunablePaddingService;
@Inject Lazy<UiOffloadThread> mUiOffloadThread;
@Inject Lazy<LightBarController> mLightBarController;
@Inject Lazy<OverviewProxyService> mOverviewProxyService;
@@ -177,7 +175,6 @@ public class Dependency {
mProviders.put(FragmentService.class, mFragmentService::get);
mProviders.put(VolumeDialogController.class, mVolumeDialogController::get);
mProviders.put(MetricsLogger.class, mMetricsLogger::get);
- mProviders.put(TunablePaddingService.class, mTunablePaddingService::get);
mProviders.put(UiOffloadThread.class, mUiOffloadThread::get);
mProviders.put(LightBarController.class, mLightBarController::get);
mProviders.put(OverviewProxyService.class, mOverviewProxyService::get);
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationSettingsController.java b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationSettingsController.java
index b4530ace68d6..ed7062b5a335 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationSettingsController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationSettingsController.java
@@ -26,6 +26,7 @@ import android.content.res.Configuration;
import android.util.Range;
import android.view.WindowManager;
+import com.android.internal.accessibility.common.MagnificationConstants;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
import com.android.systemui.util.settings.SecureSettings;
@@ -40,7 +41,8 @@ import com.android.systemui.util.settings.SecureSettings;
public class MagnificationSettingsController implements ComponentCallbacks {
// It should be consistent with the value defined in WindowMagnificationGestureHandler.
- private static final Range<Float> A11Y_ACTION_SCALE_RANGE = new Range<>(1.0f, 8.0f);
+ private static final Range<Float> A11Y_ACTION_SCALE_RANGE =
+ new Range<>(1.0f, MagnificationConstants.SCALE_MAX_VALUE);
private final Context mContext;
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java
index f2a68a8d9fd7..5f6f21a6845b 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java
@@ -55,7 +55,6 @@ import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.SeekBar;
import android.widget.Switch;
-import android.widget.TextView;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
@@ -90,7 +89,6 @@ class WindowMagnificationSettings implements MagnificationGestureDetector.OnGest
private SeekBarWithIconButtonsView mZoomSeekbar;
private LinearLayout mAllowDiagonalScrollingView;
- private TextView mAllowDiagonalScrollingTitle;
private Switch mAllowDiagonalScrollingSwitch;
private LinearLayout mPanelView;
private LinearLayout mSettingView;
@@ -98,7 +96,6 @@ class WindowMagnificationSettings implements MagnificationGestureDetector.OnGest
private ImageButton mMediumButton;
private ImageButton mLargeButton;
private Button mDoneButton;
- private TextView mSizeTitle;
private Button mEditButton;
private ImageButton mFullScreenButton;
private int mLastSelectedButtonIndex = MagnificationSize.NONE;
@@ -522,11 +519,8 @@ class WindowMagnificationSettings implements MagnificationGestureDetector.OnGest
mMediumButton = mSettingView.findViewById(R.id.magnifier_medium_button);
mLargeButton = mSettingView.findViewById(R.id.magnifier_large_button);
mDoneButton = mSettingView.findViewById(R.id.magnifier_done_button);
- mSizeTitle = mSettingView.findViewById(R.id.magnifier_size_title);
mEditButton = mSettingView.findViewById(R.id.magnifier_edit_button);
mFullScreenButton = mSettingView.findViewById(R.id.magnifier_full_button);
- mAllowDiagonalScrollingTitle =
- mSettingView.findViewById(R.id.magnifier_horizontal_lock_title);
mZoomSeekbar = mSettingView.findViewById(R.id.magnifier_zoom_slider);
mZoomSeekbar.setMax((int) (mZoomSeekbar.getChangeMagnitude()
@@ -550,8 +544,6 @@ class WindowMagnificationSettings implements MagnificationGestureDetector.OnGest
mDoneButton.setOnClickListener(mButtonClickListener);
mFullScreenButton.setOnClickListener(mButtonClickListener);
mEditButton.setOnClickListener(mButtonClickListener);
- mSizeTitle.setSelected(true);
- mAllowDiagonalScrollingTitle.setSelected(true);
mSettingView.setOnApplyWindowInsetsListener((v, insets) -> {
// Adds a pending post check to avoiding redundant calculation because this callback
@@ -578,6 +570,7 @@ class WindowMagnificationSettings implements MagnificationGestureDetector.OnGest
// CONFIG_FONT_SCALE: font size change
// CONFIG_LOCALE: language change
// CONFIG_DENSITY: display size change
+ mParams.width = getPanelWidth(mContext);
mParams.accessibilityTitle = getAccessibilityWindowTitle(mContext);
boolean showSettingPanelAfterConfigChange = mIsVisible;
@@ -660,9 +653,22 @@ class WindowMagnificationSettings implements MagnificationGestureDetector.OnGest
mCallback.onEditMagnifierSizeMode(enable);
}
- private static LayoutParams createLayoutParams(Context context) {
+ private int getPanelWidth(Context context) {
+ // The magnification settings panel width is limited to the minimum of
+ // 1. display width
+ // 2. panel done button width + left and right padding
+ // So we can directly calculate the proper panel width at runtime
+ int displayWidth = mWindowManager.getCurrentWindowMetrics().getBounds().width();
+ int contentWidth = context.getResources()
+ .getDimensionPixelSize(R.dimen.magnification_setting_button_done_width);
+ int padding = context.getResources()
+ .getDimensionPixelSize(R.dimen.magnification_setting_background_padding);
+ return Math.min(displayWidth, contentWidth + 2 * padding);
+ }
+
+ private LayoutParams createLayoutParams(Context context) {
final LayoutParams params = new LayoutParams(
- LayoutParams.WRAP_CONTENT,
+ getPanelWidth(context),
LayoutParams.WRAP_CONTENT,
LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
LayoutParams.FLAG_NOT_FOCUSABLE,
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java
index 4a28d8b05661..27ded747fd55 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java
@@ -515,7 +515,7 @@ class MenuViewLayer extends FrameLayout implements
List<ResolveInfo> activities = packageManager.queryIntentActivities(intent,
PackageManager.ResolveInfoFlags.of(PackageManager.MATCH_DEFAULT_ONLY));
if (!activities.isEmpty()) {
- mContext.startActivity(intent);
+ mContext.startActivityAsUser(intent, UserHandle.CURRENT);
mStatusBarManager.collapsePanels();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java
index 961d6aa1b821..f041f4d5963f 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java
@@ -186,7 +186,7 @@ public class HearingDevicesDialogDelegate implements SystemUIDialog.Delegate,
}
@Override
- public void onDeviceItemGearClicked(@NonNull DeviceItem deviceItem, @NonNull View view) {
+ public void onDeviceItemGearClicked(@NonNull DeviceItem deviceItem, @NonNull View view) {
dismissDialogIfExists();
Intent intent = new Intent(ACTION_BLUETOOTH_DEVICE_DETAILS);
Bundle bundle = new Bundle();
@@ -198,7 +198,7 @@ public class HearingDevicesDialogDelegate implements SystemUIDialog.Delegate,
}
@Override
- public void onDeviceItemOnClicked(@NonNull DeviceItem deviceItem, @NonNull View view) {
+ public void onDeviceItemOnClicked(@NonNull DeviceItem deviceItem, @NonNull View view) {
CachedBluetoothDevice cachedBluetoothDevice = deviceItem.getCachedBluetoothDevice();
switch (deviceItem.getType()) {
case ACTIVE_MEDIA_BLUETOOTH_DEVICE, CONNECTED_BLUETOOTH_DEVICE ->
@@ -226,8 +226,8 @@ public class HearingDevicesDialogDelegate implements SystemUIDialog.Delegate,
final int activePresetIndex = mPresetsController.getActivePresetIndex();
refreshPresetInfoAdapter(presetInfos, activePresetIndex);
mPresetSpinner.setVisibility(
- (activeHearingDevice != null && !mPresetInfoAdapter.isEmpty()) ? VISIBLE
- : GONE);
+ (activeHearingDevice != null && activeHearingDevice.isConnectedHapClientDevice()
+ && !mPresetInfoAdapter.isEmpty()) ? VISIBLE : GONE);
});
}
@@ -303,6 +303,11 @@ public class HearingDevicesDialogDelegate implements SystemUIDialog.Delegate,
mLocalBluetoothManager.getEventManager().unregisterCallback(this);
}
+ @VisibleForTesting
+ void setHearingDevicesPresetsController(HearingDevicesPresetsController controller) {
+ mPresetsController = controller;
+ }
+
private void setupDeviceListView(SystemUIDialog dialog) {
mDeviceList.setLayoutManager(new LinearLayoutManager(dialog.getContext()));
mHearingDeviceItemList = getHearingDevicesList();
@@ -311,12 +316,15 @@ public class HearingDevicesDialogDelegate implements SystemUIDialog.Delegate,
}
private void setupPresetSpinner(SystemUIDialog dialog) {
- mPresetsController = new HearingDevicesPresetsController(mProfileManager, mPresetCallback);
+ if (mPresetsController == null) {
+ mPresetsController = new HearingDevicesPresetsController(mProfileManager,
+ mPresetCallback);
+ }
final CachedBluetoothDevice activeHearingDevice = getActiveHearingDevice(
mHearingDeviceItemList);
mPresetsController.setActiveHearingDevice(activeHearingDevice);
- mPresetInfoAdapter = new ArrayAdapter<String>(dialog.getContext(),
+ mPresetInfoAdapter = new ArrayAdapter<>(dialog.getContext(),
R.layout.hearing_devices_preset_spinner_selected,
R.id.hearing_devices_preset_option_text);
mPresetInfoAdapter.setDropDownViewResource(
@@ -350,7 +358,8 @@ public class HearingDevicesDialogDelegate implements SystemUIDialog.Delegate,
final int activePresetIndex = mPresetsController.getActivePresetIndex();
refreshPresetInfoAdapter(presetInfos, activePresetIndex);
mPresetSpinner.setVisibility(
- (activeHearingDevice != null && !mPresetInfoAdapter.isEmpty()) ? VISIBLE : GONE);
+ (activeHearingDevice != null && activeHearingDevice.isConnectedHapClientDevice()
+ && !mPresetInfoAdapter.isEmpty()) ? VISIBLE : GONE);
}
private void setupPairNewDeviceButton(SystemUIDialog dialog, @Visibility int visibility) {
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 1d11dfbc48a8..4984fc61c8f8 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
@@ -102,11 +102,7 @@ constructor(
if (alternateBouncerSupported) {
combine(
keyguardTransitionInteractor.get().currentKeyguardState,
- if (SceneContainerFlag.isEnabled) {
- sceneInteractor.get().currentScene
- } else {
- flowOf(Scenes.Lockscreen)
- },
+ sceneInteractor.get().currentScene,
::Pair
)
.flatMapLatest { (currentKeyguardState, transitionState) ->
@@ -220,6 +216,7 @@ constructor(
return (systemClock.uptimeMillis() - bouncerRepository.lastAlternateBouncerVisibleTime) >
MIN_VISIBILITY_DURATION_UNTIL_TOUCHES_DISMISS_ALTERNATE_BOUNCER_MS
}
+
/**
* Should only be called through StatusBarKeyguardViewManager which propagates the source of
* truth to other concerned controllers. Will hide the alternate bouncer if it's no longer
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayView.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayView.java
index ba236ba016ff..1762d82b3237 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayView.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayView.java
@@ -18,8 +18,6 @@ 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;
@@ -61,7 +59,6 @@ import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
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;
@@ -152,66 +149,47 @@ public class ClipboardOverlayView extends DraggableConstraintLayout {
}
private void bindDefaultActionChips() {
- if (screenshotShelfUi2()) {
- mActionButtonViewBinder.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),
- true),
- new Function0<>() {
- @Override
- public Unit invoke() {
- if (mClipboardCallbacks != null) {
- mClipboardCallbacks.onRemoteCopyButtonTapped();
- }
- return null;
+ mActionButtonViewBinder.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),
+ true),
+ new Function0<>() {
+ @Override
+ public Unit invoke() {
+ if (mClipboardCallbacks != null) {
+ mClipboardCallbacks.onRemoteCopyButtonTapped();
}
- }));
- mActionButtonViewBinder.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),
- true),
- new Function0<>() {
- @Override
- public Unit invoke() {
- if (mClipboardCallbacks != null) {
- mClipboardCallbacks.onShareButtonTapped();
- }
- return null;
+ return null;
+ }
+ }));
+ mActionButtonViewBinder.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),
+ true),
+ new Function0<>() {
+ @Override
+ public Unit invoke() {
+ if (mClipboardCallbacks != null) {
+ mClipboardCallbacks.onShareButtonTapped();
}
- }));
- } 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));
- }
+ return null;
+ }
+ }));
}
@Override
public void setCallbacks(SwipeDismissCallbacks callbacks) {
super.setCallbacks(callbacks);
ClipboardOverlayCallbacks clipboardCallbacks = (ClipboardOverlayCallbacks) callbacks;
- if (!screenshotShelfUi2()) {
- mShareChip.setOnClickListener(v -> clipboardCallbacks.onShareButtonTapped());
- mRemoteCopyChip.setOnClickListener(v -> clipboardCallbacks.onRemoteCopyButtonTapped());
- }
mDismissButton.setOnClickListener(v -> clipboardCallbacks.onDismissButtonTapped());
mClipboardPreview.setOnClickListener(v -> clipboardCallbacks.onPreviewTapped());
mMinimizedPreview.setOnClickListener(v -> clipboardCallbacks.onMinimizedViewTapped());
@@ -495,12 +473,7 @@ public class ClipboardOverlayView extends DraggableConstraintLayout {
void setActionChip(RemoteAction action, Runnable onFinish) {
mActionContainerBackground.setVisibility(View.VISIBLE);
- View chip;
- if (screenshotShelfUi2()) {
- chip = constructShelfActionChip(action, onFinish);
- } else {
- chip = constructActionChip(action, onFinish);
- }
+ View chip = constructShelfActionChip(action, onFinish);
mActionContainer.addView(chip);
mActionChips.add(chip);
}
@@ -534,17 +507,6 @@ public class ClipboardOverlayView extends DraggableConstraintLayout {
return chip;
}
- private OverlayActionChip constructActionChip(RemoteAction action, Runnable onFinish) {
- OverlayActionChip chip = (OverlayActionChip) LayoutInflater.from(mContext).inflate(
- R.layout.overlay_action_chip, mActionContainer, false);
- chip.setText(action.getTitle());
- chip.setContentDescription(action.getTitle());
- chip.setIcon(action.getIcon(), false);
- chip.setPendingIntent(action.getActionIntent(), onFinish);
- chip.setAlpha(1);
- return chip;
- }
-
private static void updateTextSize(CharSequence text, TextView textView) {
Paint paint = new Paint(textView.getPaint());
Resources res = textView.getResources();
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 740a93eb081c..ff9fba4c03f1 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/dagger/ClipboardOverlayModule.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/dagger/ClipboardOverlayModule.java
@@ -18,8 +18,6 @@ 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;
@@ -59,13 +57,8 @@ public interface ClipboardOverlayModule {
*/
@Provides
static ClipboardOverlayView provideClipboardOverlayView(@OverlayWindowContext Context context) {
- 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);
- }
+ return (ClipboardOverlayView) LayoutInflater.from(context).inflate(
+ R.layout.clipboard_overlay, null);
}
@Qualifier
diff --git a/packages/SystemUI/src/com/android/systemui/communal/CommunalBackupRestoreStartable.kt b/packages/SystemUI/src/com/android/systemui/communal/CommunalBackupRestoreStartable.kt
index cdeeb6ff0b23..7abad1448318 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/CommunalBackupRestoreStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/CommunalBackupRestoreStartable.kt
@@ -21,6 +21,9 @@ import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
+import android.database.ContentObserver
+import android.os.Handler
+import android.provider.Settings.Secure.USER_SETUP_COMPLETE
import com.android.systemui.CoreStartable
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.communal.domain.interactor.CommunalInteractor
@@ -29,6 +32,7 @@ import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.core.Logger
import com.android.systemui.log.dagger.CommunalLog
+import com.android.systemui.util.settings.SecureSettings
import javax.inject.Inject
@SysUISingleton
@@ -38,10 +42,15 @@ constructor(
private val broadcastDispatcher: BroadcastDispatcher,
private val communalInteractor: CommunalInteractor,
@CommunalLog logBuffer: LogBuffer,
+ private val secureSettings: SecureSettings,
+ handler: Handler,
) : CoreStartable, BroadcastReceiver() {
private val logger = Logger(logBuffer, TAG)
+ private var oldToNewWidgetIdMap = emptyMap<Int, Int>()
+ private var userSetupComplete = false
+
override fun start() {
broadcastDispatcher.registerReceiver(
receiver = this,
@@ -73,8 +82,53 @@ constructor(
return
}
- val oldToNewWidgetIdMap = oldIds.zip(newIds).toMap()
- communalInteractor.restoreWidgets(oldToNewWidgetIdMap)
+ oldToNewWidgetIdMap = oldIds.zip(newIds).toMap()
+
+ logger.i({ "On old to new widget ids mapping updated: $str1" }) {
+ str1 = oldToNewWidgetIdMap.toString()
+ }
+
+ maybeRestoreWidgets()
+
+ // Start observing if user setup is not complete
+ if (!userSetupComplete) {
+ startObservingUserSetupComplete()
+ }
+ }
+
+ private val userSetupObserver =
+ object : ContentObserver(handler) {
+ override fun onChange(selfChange: Boolean) {
+ maybeRestoreWidgets()
+
+ // Stop observing once user setup is complete
+ if (userSetupComplete) {
+ stopObservingUserSetupComplete()
+ }
+ }
+ }
+
+ private fun maybeRestoreWidgets() {
+ val newValue = secureSettings.getInt(USER_SETUP_COMPLETE) > 0
+
+ if (userSetupComplete != newValue) {
+ userSetupComplete = newValue
+ logger.i({ "User setup complete: $bool1" }) { bool1 = userSetupComplete }
+ }
+
+ if (userSetupComplete && oldToNewWidgetIdMap.isNotEmpty()) {
+ logger.i("Starting to restore widgets")
+ communalInteractor.restoreWidgets(oldToNewWidgetIdMap.toMap())
+ oldToNewWidgetIdMap = emptyMap()
+ }
+ }
+
+ private fun startObservingUserSetupComplete() {
+ secureSettings.registerContentObserverSync(USER_SETUP_COMPLETE, userSetupObserver)
+ }
+
+ private fun stopObservingUserSetupComplete() {
+ secureSettings.unregisterContentObserverSync(userSetupObserver)
}
companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/communal/CommunalOngoingContentStartable.kt b/packages/SystemUI/src/com/android/systemui/communal/CommunalOngoingContentStartable.kt
new file mode 100644
index 000000000000..78016c6664a1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/communal/CommunalOngoingContentStartable.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.communal
+
+import com.android.systemui.CoreStartable
+import com.android.systemui.communal.data.repository.CommunalMediaRepository
+import com.android.systemui.communal.data.repository.CommunalSmartspaceRepository
+import com.android.systemui.communal.domain.interactor.CommunalInteractor
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.flags.FeatureFlagsClassic
+import com.android.systemui.flags.Flags
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
+
+@SysUISingleton
+class CommunalOngoingContentStartable
+@Inject
+constructor(
+ @Background val bgScope: CoroutineScope,
+ private val communalInteractor: CommunalInteractor,
+ private val communalMediaRepository: CommunalMediaRepository,
+ private val communalSmartspaceRepository: CommunalSmartspaceRepository,
+ private val featureFlags: FeatureFlagsClassic,
+) : CoreStartable {
+
+ override fun start() {
+ if (
+ !featureFlags.isEnabled(Flags.COMMUNAL_SERVICE_ENABLED) ||
+ !com.android.systemui.Flags.communalHub()
+ ) {
+ return
+ }
+
+ bgScope.launch {
+ communalInteractor.isCommunalEnabled.collect { enabled ->
+ if (enabled) {
+ communalMediaRepository.startListening()
+ communalSmartspaceRepository.startListening()
+ } else {
+ communalMediaRepository.stopListening()
+ communalSmartspaceRepository.stopListening()
+ }
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt b/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
index 88c3f9f6af2e..bde6f42b16af 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
@@ -18,7 +18,9 @@ package com.android.systemui.communal
import android.provider.Settings
import com.android.compose.animation.scene.SceneKey
+import com.android.compose.animation.scene.TransitionKey
import com.android.systemui.CoreStartable
+import com.android.systemui.Flags.communalHub
import com.android.systemui.communal.domain.interactor.CommunalInteractor
import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor
import com.android.systemui.communal.shared.model.CommunalScenes
@@ -28,6 +30,8 @@ import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dock.DockManager
+import com.android.systemui.flags.FeatureFlagsClassic
+import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState
@@ -74,6 +78,7 @@ constructor(
private val systemSettings: SystemSettings,
centralSurfacesOpt: Optional<CentralSurfaces>,
private val notificationShadeWindowController: NotificationShadeWindowController,
+ private val featureFlagsClassic: FeatureFlagsClassic,
@Application private val applicationScope: CoroutineScope,
@Background private val bgScope: CoroutineScope,
@Main private val mainDispatcher: CoroutineDispatcher,
@@ -86,13 +91,21 @@ constructor(
private val centralSurfaces: CentralSurfaces? by centralSurfacesOpt
+ private val flagEnabled: Boolean by lazy {
+ featureFlagsClassic.isEnabled(Flags.COMMUNAL_SERVICE_ENABLED) && communalHub()
+ }
+
override fun start() {
+ if (!flagEnabled) {
+ return
+ }
+
// Handle automatically switching based on keyguard state.
keyguardTransitionInteractor.startedKeyguardTransitionStep
.mapLatest(::determineSceneAfterTransition)
.filterNotNull()
- .onEach { nextScene ->
- communalSceneInteractor.changeScene(nextScene, CommunalTransitionKeys.SimpleFade)
+ .onEach { (nextScene, nextTransition) ->
+ communalSceneInteractor.changeScene(nextScene, nextTransition)
}
.launchIn(applicationScope)
@@ -188,7 +201,7 @@ constructor(
private suspend fun determineSceneAfterTransition(
lastStartedTransition: TransitionStep,
- ): SceneKey? {
+ ): Pair<SceneKey, TransitionKey>? {
val to = lastStartedTransition.to
val from = lastStartedTransition.from
val docked = dockManager.isDocked
@@ -201,22 +214,27 @@ constructor(
// underneath the hub is shown. When launching activities over lockscreen, we only
// change scenes once the activity launch animation is finished, so avoid
// changing the scene here.
- CommunalScenes.Blank
+ Pair(CommunalScenes.Blank, CommunalTransitionKeys.SimpleFade)
}
to == KeyguardState.GLANCEABLE_HUB && from == KeyguardState.OCCLUDED -> {
// When transitioning to the hub from an occluded state, fade out the hub without
// doing any translation.
- CommunalScenes.Communal
+ Pair(CommunalScenes.Communal, CommunalTransitionKeys.SimpleFade)
}
// Transitioning to Blank scene when entering the edit mode will be handled separately
// with custom animations.
to == KeyguardState.GONE && !communalInteractor.editModeOpen.value ->
- CommunalScenes.Blank
+ Pair(CommunalScenes.Blank, CommunalTransitionKeys.SimpleFade)
!docked && !KeyguardState.deviceIsAwakeInState(to) -> {
// If the user taps the screen and wakes the device within this timeout, we don't
// want to dismiss the hub
delay(AWAKE_DEBOUNCE_DELAY)
- CommunalScenes.Blank
+ Pair(CommunalScenes.Blank, CommunalTransitionKeys.SimpleFade)
+ }
+ from == KeyguardState.DOZING && to == KeyguardState.GLANCEABLE_HUB -> {
+ // Make sure the communal hub is showing (immediately, not fading in) when
+ // transitioning from dozing to hub.
+ Pair(CommunalScenes.Communal, CommunalTransitionKeys.Immediately)
}
else -> null
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalModule.kt b/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalModule.kt
index 2406cc6bcea2..3d201a36417b 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalModule.kt
@@ -23,6 +23,7 @@ import com.android.systemui.communal.data.repository.CommunalMediaRepositoryModu
import com.android.systemui.communal.data.repository.CommunalPrefsRepositoryModule
import com.android.systemui.communal.data.repository.CommunalRepositoryModule
import com.android.systemui.communal.data.repository.CommunalSettingsRepositoryModule
+import com.android.systemui.communal.data.repository.CommunalSmartspaceRepositoryModule
import com.android.systemui.communal.data.repository.CommunalTutorialRepositoryModule
import com.android.systemui.communal.data.repository.CommunalWidgetRepositoryModule
import com.android.systemui.communal.shared.model.CommunalScenes
@@ -52,6 +53,8 @@ import kotlinx.coroutines.CoroutineScope
CommunalWidgetModule::class,
CommunalPrefsRepositoryModule::class,
CommunalSettingsRepositoryModule::class,
+ CommunalSmartspaceRepositoryModule::class,
+ CommunalStartableModule::class,
]
)
interface CommunalModule {
diff --git a/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalStartableModule.kt b/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalStartableModule.kt
new file mode 100644
index 000000000000..74a2cd3f22c4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalStartableModule.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.communal.dagger
+
+import com.android.systemui.CoreStartable
+import com.android.systemui.communal.CommunalBackupRestoreStartable
+import com.android.systemui.communal.CommunalDreamStartable
+import com.android.systemui.communal.CommunalOngoingContentStartable
+import com.android.systemui.communal.CommunalSceneStartable
+import com.android.systemui.communal.log.CommunalLoggerStartable
+import com.android.systemui.communal.widgets.CommunalAppWidgetHostStartable
+import dagger.Binds
+import dagger.Module
+import dagger.multibindings.ClassKey
+import dagger.multibindings.IntoMap
+
+@Module
+interface CommunalStartableModule {
+ @Binds
+ @IntoMap
+ @ClassKey(CommunalLoggerStartable::class)
+ fun bindCommunalLoggerStartable(impl: CommunalLoggerStartable): CoreStartable
+
+ @Binds
+ @IntoMap
+ @ClassKey(CommunalSceneStartable::class)
+ fun bindCommunalSceneStartable(impl: CommunalSceneStartable): CoreStartable
+
+ @Binds
+ @IntoMap
+ @ClassKey(CommunalDreamStartable::class)
+ fun bindCommunalDreamStartable(impl: CommunalDreamStartable): CoreStartable
+
+ @Binds
+ @IntoMap
+ @ClassKey(CommunalAppWidgetHostStartable::class)
+ fun bindCommunalAppWidgetHostStartable(impl: CommunalAppWidgetHostStartable): CoreStartable
+
+ @Binds
+ @IntoMap
+ @ClassKey(CommunalBackupRestoreStartable::class)
+ fun bindCommunalBackupRestoreStartable(impl: CommunalBackupRestoreStartable): CoreStartable
+
+ @Binds
+ @IntoMap
+ @ClassKey(CommunalOngoingContentStartable::class)
+ fun bindCommunalOngoingContentStartable(impl: CommunalOngoingContentStartable): CoreStartable
+}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/backup/CommunalBackupUtils.kt b/packages/SystemUI/src/com/android/systemui/communal/data/backup/CommunalBackupUtils.kt
index a8e5174494a1..c3d2683ce953 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/data/backup/CommunalBackupUtils.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/data/backup/CommunalBackupUtils.kt
@@ -43,11 +43,13 @@ class CommunalBackupUtils(
val widgetsFromDb = runBlocking { database.communalWidgetDao().getWidgets().first() }
val widgetsState = mutableListOf<CommunalHubState.CommunalWidgetItem>()
widgetsFromDb.keys.forEach { rankItem ->
+ val widget = widgetsFromDb[rankItem]!!
widgetsState.add(
CommunalHubState.CommunalWidgetItem().apply {
rank = rankItem.rank
- widgetId = widgetsFromDb[rankItem]!!.widgetId
- componentName = widgetsFromDb[rankItem]?.componentName
+ widgetId = widget.widgetId
+ componentName = widget.componentName
+ userSerialNumber = widget.userSerialNumber
}
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/db/CommunalDatabase.kt b/packages/SystemUI/src/com/android/systemui/communal/data/db/CommunalDatabase.kt
index 3ce81094b696..dff63527ba05 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/data/db/CommunalDatabase.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/data/db/CommunalDatabase.kt
@@ -17,17 +17,21 @@
package com.android.systemui.communal.data.db
import android.content.Context
+import android.util.Log
import androidx.annotation.VisibleForTesting
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
+import androidx.room.migration.Migration
+import androidx.sqlite.db.SupportSQLiteDatabase
import com.android.systemui.res.R
-@Database(entities = [CommunalWidgetItem::class, CommunalItemRank::class], version = 1)
+@Database(entities = [CommunalWidgetItem::class, CommunalItemRank::class], version = 2)
abstract class CommunalDatabase : RoomDatabase() {
abstract fun communalWidgetDao(): CommunalWidgetDao
companion object {
+ private const val TAG = "CommunalDatabase"
private var instance: CommunalDatabase? = null
/**
@@ -51,7 +55,8 @@ abstract class CommunalDatabase : RoomDatabase() {
context.resources.getString(R.string.config_communalDatabase)
)
.also { builder ->
- builder.fallbackToDestructiveMigration(dropAllTables = false)
+ builder.addMigrations(MIGRATION_1_2)
+ builder.fallbackToDestructiveMigration(dropAllTables = true)
callback?.let { callback -> builder.addCallback(callback) }
}
.build()
@@ -64,5 +69,23 @@ abstract class CommunalDatabase : RoomDatabase() {
fun setInstance(database: CommunalDatabase) {
instance = database
}
+
+ /**
+ * This migration adds a user_serial_number column and sets its default value as
+ * [CommunalWidgetItem.USER_SERIAL_NUMBER_UNDEFINED]. Work profile widgets added before the
+ * migration still work as expected, but they would be backed up as personal.
+ */
+ @VisibleForTesting
+ val MIGRATION_1_2 =
+ object : Migration(1, 2) {
+ override fun migrate(db: SupportSQLiteDatabase) {
+ Log.i(TAG, "Migrating from version 1 to 2")
+ db.execSQL(
+ "ALTER TABLE communal_widget_table " +
+ "ADD COLUMN user_serial_number INTEGER NOT NULL DEFAULT " +
+ "${CommunalWidgetItem.USER_SERIAL_NUMBER_UNDEFINED}"
+ )
+ }
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/db/CommunalEntities.kt b/packages/SystemUI/src/com/android/systemui/communal/data/db/CommunalEntities.kt
index 0d5336ab8540..e33aead11842 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/data/db/CommunalEntities.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/data/db/CommunalEntities.kt
@@ -29,7 +29,28 @@ data class CommunalWidgetItem(
@ColumnInfo(name = "component_name") val componentName: String,
/** Reference the id of an item persisted in the glanceable hub */
@ColumnInfo(name = "item_id") val itemId: Long,
-)
+ /**
+ * A serial number of the user that the widget provider is associated with. For example, a work
+ * profile widget.
+ *
+ * A serial number may be different from its user id in that user ids may be recycled but serial
+ * numbers are unique until the device is wiped.
+ *
+ * Most commonly, this value would be 0 for the primary user, and 10 for the work profile.
+ */
+ @ColumnInfo(name = "user_serial_number", defaultValue = "$USER_SERIAL_NUMBER_UNDEFINED")
+ val userSerialNumber: Int,
+) {
+ companion object {
+ /**
+ * The user serial number associated with the widget is undefined.
+ *
+ * This should only happen for widgets migrated from V1 before user serial number was
+ * included in the schema.
+ */
+ const val USER_SERIAL_NUMBER_UNDEFINED = -1
+ }
+}
@Entity(tableName = "communal_item_rank_table")
data class CommunalItemRank(
diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/db/CommunalWidgetDao.kt b/packages/SystemUI/src/com/android/systemui/communal/data/db/CommunalWidgetDao.kt
index d174fd1c97ea..933a25a21578 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/data/db/CommunalWidgetDao.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/data/db/CommunalWidgetDao.kt
@@ -17,6 +17,7 @@
package com.android.systemui.communal.data.db
import android.content.ComponentName
+import android.os.UserManager
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Query
@@ -26,7 +27,7 @@ import androidx.sqlite.db.SupportSQLiteDatabase
import com.android.systemui.communal.nano.CommunalHubState
import com.android.systemui.communal.widgets.CommunalWidgetHost
import com.android.systemui.communal.widgets.CommunalWidgetModule.Companion.DEFAULT_WIDGETS
-import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.core.Logger
@@ -34,58 +35,96 @@ import com.android.systemui.log.dagger.CommunalLog
import javax.inject.Inject
import javax.inject.Named
import javax.inject.Provider
-import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.launch
-import kotlinx.coroutines.withContext
/**
* Callback that will be invoked when the Room database is created. Then the database will be
* populated with pre-configured default widgets to be rendered in the glanceable hub.
*/
+@SysUISingleton
class DefaultWidgetPopulation
@Inject
constructor(
- @Application private val applicationScope: CoroutineScope,
- @Background private val bgDispatcher: CoroutineDispatcher,
+ @Background private val bgScope: CoroutineScope,
private val communalWidgetHost: CommunalWidgetHost,
private val communalWidgetDaoProvider: Provider<CommunalWidgetDao>,
@Named(DEFAULT_WIDGETS) private val defaultWidgets: Array<String>,
@CommunalLog logBuffer: LogBuffer,
+ private val userManager: UserManager,
) : RoomDatabase.Callback() {
companion object {
private const val TAG = "DefaultWidgetPopulation"
}
+
private val logger = Logger(logBuffer, TAG)
+ /**
+ * Reason for skipping default widgets population. Do not skip if this value is
+ * [SkipReason.NONE].
+ */
+ private var skipReason = SkipReason.NONE
+
override fun onCreate(db: SupportSQLiteDatabase) {
super.onCreate(db)
- applicationScope.launch {
- addDefaultWidgets()
- logger.i("Default widgets were populated in the database.")
+
+ if (skipReason != SkipReason.NONE) {
+ logger.i("Skipped populating default widgets. Reason: $skipReason")
+ return
}
- }
- // Read default widgets from config.xml and populate the database.
- private suspend fun addDefaultWidgets() =
- withContext(bgDispatcher) {
+ bgScope.launch {
+ // Default widgets should be associated with the main user.
+ val user = userManager.mainUser
+
+ if (user == null) {
+ logger.w(
+ "Skipped populating default widgets. Reason: device does not have a main user"
+ )
+ return@launch
+ }
+
+ val userSerialNumber = userManager.getUserSerialNumber(user.identifier)
+
defaultWidgets.forEachIndexed { index, name ->
val provider = ComponentName.unflattenFromString(name)
provider?.let {
- val id = communalWidgetHost.allocateIdAndBindWidget(provider)
+ val id = communalWidgetHost.allocateIdAndBindWidget(provider, user)
id?.let {
communalWidgetDaoProvider
.get()
.addWidget(
widgetId = id,
- provider = provider,
- priority = defaultWidgets.size - index
+ componentName = name,
+ priority = defaultWidgets.size - index,
+ userSerialNumber = userSerialNumber,
)
}
}
}
+
+ logger.i("Populated default widgets in the database.")
}
+ }
+
+ /**
+ * Skip populating default widgets in the Glanceable Hub when the database is created. This has
+ * no effect if default widgets have been populated already.
+ *
+ * @param skipReason Reason for skipping the default widgets population.
+ */
+ fun skipDefaultWidgetsPopulation(skipReason: SkipReason) {
+ this.skipReason = skipReason
+ }
+
+ /** Reason for skipping default widgets population. */
+ enum class SkipReason {
+ /** Do not skip. */
+ NONE,
+ /** Widgets are restored from a backup. */
+ RESTORED_FROM_BACKUP,
+ }
}
@Dao
@@ -106,10 +145,16 @@ interface CommunalWidgetDao {
fun deleteItemRankById(itemId: Long)
@Query(
- "INSERT INTO communal_widget_table(widget_id, component_name, item_id) " +
- "VALUES(:widgetId, :componentName, :itemId)"
+ "INSERT INTO communal_widget_table" +
+ "(widget_id, component_name, item_id, user_serial_number) " +
+ "VALUES(:widgetId, :componentName, :itemId, :userSerialNumber)"
)
- fun insertWidget(widgetId: Int, componentName: String, itemId: Long): Long
+ fun insertWidget(
+ widgetId: Int,
+ componentName: String,
+ itemId: Long,
+ userSerialNumber: Int,
+ ): Long
@Query("INSERT INTO communal_item_rank_table(rank) VALUES(:rank)")
fun insertItemRank(rank: Int): Long
@@ -132,28 +177,41 @@ interface CommunalWidgetDao {
}
@Transaction
- fun addWidget(widgetId: Int, provider: ComponentName, priority: Int): Long {
+ fun addWidget(
+ widgetId: Int,
+ provider: ComponentName,
+ priority: Int,
+ userSerialNumber: Int,
+ ): Long {
return addWidget(
widgetId = widgetId,
componentName = provider.flattenToString(),
priority = priority,
+ userSerialNumber = userSerialNumber,
)
}
@Transaction
- fun addWidget(widgetId: Int, componentName: String, priority: Int): Long {
+ fun addWidget(
+ widgetId: Int,
+ componentName: String,
+ priority: Int,
+ userSerialNumber: Int,
+ ): Long {
return insertWidget(
widgetId = widgetId,
componentName = componentName,
itemId = insertItemRank(priority),
+ userSerialNumber = userSerialNumber,
)
}
@Transaction
fun deleteWidgetById(widgetId: Int): Boolean {
val widget =
- getWidgetByIdNow(widgetId) ?: // no entry to delete from db
- return false
+ getWidgetByIdNow(widgetId)
+ ?: // no entry to delete from db
+ return false
deleteItemRankById(widget.itemId)
deleteWidgets(widget)
@@ -166,6 +224,8 @@ interface CommunalWidgetDao {
clearCommunalWidgetsTable()
clearCommunalItemRankTable()
- state.widgets.forEach { addWidget(it.widgetId, it.componentName, it.rank) }
+ state.widgets.forEach {
+ addWidget(it.widgetId, it.componentName, it.rank, it.userSerialNumber)
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/model/CommunalSmartspaceTimer.kt b/packages/SystemUI/src/com/android/systemui/communal/data/model/CommunalSmartspaceTimer.kt
new file mode 100644
index 000000000000..ff9dddd7c516
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/communal/data/model/CommunalSmartspaceTimer.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.communal.data.model
+
+import android.widget.RemoteViews
+
+/** Data model of a smartspace timer in the Glanceable Hub. */
+data class CommunalSmartspaceTimer(
+ /** Unique id that identifies the timer. */
+ val smartspaceTargetId: String,
+ /** Timestamp in milliseconds of when the timer was created. */
+ val createdTimestampMillis: Long,
+ /** Remote views for the timer that is rendered in Glanceable Hub. */
+ val remoteViews: RemoteViews,
+)
diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalMediaRepository.kt b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalMediaRepository.kt
index e5a0e5070b94..fe9154c192c5 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalMediaRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalMediaRepository.kt
@@ -30,6 +30,12 @@ import kotlinx.coroutines.flow.MutableStateFlow
/** Encapsulates the state of smartspace in communal. */
interface CommunalMediaRepository {
val mediaModel: Flow<CommunalMediaModel>
+
+ /** Start listening for media updates. */
+ fun startListening()
+
+ /** Stop listening for media updates. */
+ fun stopListening()
}
@SysUISingleton
@@ -38,29 +44,7 @@ class CommunalMediaRepositoryImpl
constructor(
private val mediaDataManager: MediaDataManager,
@CommunalTableLog tableLogBuffer: TableLogBuffer,
-) : CommunalMediaRepository {
-
- private val mediaDataListener =
- object : MediaDataManager.Listener {
- override fun onMediaDataLoaded(
- key: String,
- oldKey: String?,
- data: MediaData,
- immediately: Boolean,
- receivedSmartspaceCardLatency: Int,
- isSsReactivated: Boolean
- ) {
- updateMediaModel(data)
- }
-
- override fun onMediaDataRemoved(key: String, userInitiated: Boolean) {
- updateMediaModel()
- }
- }
-
- init {
- mediaDataManager.addListener(mediaDataListener)
- }
+) : CommunalMediaRepository, MediaDataManager.Listener {
private val _mediaModel: MutableStateFlow<CommunalMediaModel> =
MutableStateFlow(CommunalMediaModel.INACTIVE)
@@ -72,6 +56,29 @@ constructor(
initialValue = CommunalMediaModel.INACTIVE,
)
+ override fun startListening() {
+ mediaDataManager.addListener(this)
+ }
+
+ override fun stopListening() {
+ mediaDataManager.removeListener(this)
+ }
+
+ override fun onMediaDataLoaded(
+ key: String,
+ oldKey: String?,
+ data: MediaData,
+ immediately: Boolean,
+ receivedSmartspaceCardLatency: Int,
+ isSsReactivated: Boolean
+ ) {
+ updateMediaModel(data)
+ }
+
+ override fun onMediaDataRemoved(key: String, userInitiated: Boolean) {
+ updateMediaModel()
+ }
+
private fun updateMediaModel(data: MediaData? = null) {
if (mediaDataManager.hasActiveMediaOrRecommendation()) {
_mediaModel.value =
diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSmartspaceRepository.kt b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSmartspaceRepository.kt
new file mode 100644
index 000000000000..e1d9bef67490
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSmartspaceRepository.kt
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.communal.data.repository
+
+import android.app.smartspace.SmartspaceTarget
+import android.os.Parcelable
+import androidx.annotation.VisibleForTesting
+import com.android.systemui.communal.data.model.CommunalSmartspaceTimer
+import com.android.systemui.communal.smartspace.CommunalSmartspaceController
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.plugins.BcSmartspaceDataPlugin
+import com.android.systemui.util.time.SystemClock
+import java.util.concurrent.Executor
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+
+interface CommunalSmartspaceRepository {
+ /** Smartspace timer targets for the communal surface. */
+ val timers: Flow<List<CommunalSmartspaceTimer>>
+
+ /** Start listening for smartspace updates. */
+ fun startListening()
+
+ /** Stop listening for smartspace updates. */
+ fun stopListening()
+}
+
+@SysUISingleton
+class CommunalSmartspaceRepositoryImpl
+@Inject
+constructor(
+ private val communalSmartspaceController: CommunalSmartspaceController,
+ @Main private val uiExecutor: Executor,
+ private val systemClock: SystemClock,
+) : CommunalSmartspaceRepository, BcSmartspaceDataPlugin.SmartspaceTargetListener {
+
+ private val _timers: MutableStateFlow<List<CommunalSmartspaceTimer>> =
+ MutableStateFlow(emptyList())
+ override val timers: Flow<List<CommunalSmartspaceTimer>> = _timers
+
+ private var targetCreationTimes = emptyMap<String, Long>()
+
+ override fun onSmartspaceTargetsUpdated(targetsNullable: MutableList<out Parcelable>?) {
+ val targets = targetsNullable?.filterIsInstance<SmartspaceTarget>() ?: emptyList()
+ val timerTargets =
+ targets
+ .filter { target ->
+ target.featureType == SmartspaceTarget.FEATURE_TIMER &&
+ target.remoteViews != null
+ }
+ .associateBy { stableId(it.smartspaceTargetId) }
+
+ // The creation times from smartspace targets are unreliable (b/318535930). Therefore,
+ // SystemUI uses the timestamp of which a timer first appears, and caches these values to
+ // prevent timers from swapping positions in the hub.
+ targetCreationTimes =
+ timerTargets.mapValues { (stableId, _) ->
+ targetCreationTimes[stableId] ?: systemClock.currentTimeMillis()
+ }
+
+ _timers.value =
+ timerTargets.map { (stableId, target) ->
+ CommunalSmartspaceTimer(
+ // The view layer should have the instance based smartspaceTargetId instead of
+ // stable id, so that when a new instance of the timer is created, for example,
+ // when it is paused, the view should re-render its remote views.
+ smartspaceTargetId = target.smartspaceTargetId,
+ createdTimestampMillis = targetCreationTimes[stableId]!!,
+ remoteViews = target.remoteViews!!,
+ )
+ }
+ }
+
+ override fun startListening() {
+ if (android.app.smartspace.flags.Flags.remoteViews()) {
+ uiExecutor.execute {
+ communalSmartspaceController.addListener(
+ listener = this@CommunalSmartspaceRepositoryImpl
+ )
+ }
+ }
+ }
+
+ override fun stopListening() {
+ uiExecutor.execute {
+ communalSmartspaceController.removeListener(
+ listener = this@CommunalSmartspaceRepositoryImpl
+ )
+ }
+ }
+
+ companion object {
+ /**
+ * The smartspace target id is instance-based, meaning a single timer (from the user's
+ * perspective) can have multiple instances. For example, when a timer is paused, a new
+ * instance is created. To address this, SystemUI manually removes the instance id to
+ * maintain a consistent id across sessions.
+ *
+ * It is assumed that timer target ids follow this format: timer-${stableId}-${instanceId}.
+ * This function returns timer-${stableId}, stripping out the instance id.
+ */
+ @VisibleForTesting
+ fun stableId(targetId: String): String {
+ return targetId.split("-").take(2).joinToString("-")
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/smartspace/data/repository/SmartspaceRepositoryModule.kt b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSmartspaceRepositoryModule.kt
index c77bcc50b69a..b11c6d6d5d55 100644
--- a/packages/SystemUI/src/com/android/systemui/smartspace/data/repository/SmartspaceRepositoryModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSmartspaceRepositoryModule.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.
@@ -14,12 +14,15 @@
* limitations under the License.
*/
-package com.android.systemui.smartspace.data.repository
+package com.android.systemui.communal.data.repository
import dagger.Binds
import dagger.Module
@Module
-interface SmartspaceRepositoryModule {
- @Binds fun smartspaceRepository(impl: SmartspaceRepositoryImpl): SmartspaceRepository
+interface CommunalSmartspaceRepositoryModule {
+ @Binds
+ fun communalSmartspaceRepository(
+ impl: CommunalSmartspaceRepositoryImpl
+ ): CommunalSmartspaceRepository
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalWidgetRepository.kt b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalWidgetRepository.kt
index fdb797d5ba06..e65e5e5688f5 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalWidgetRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalWidgetRepository.kt
@@ -20,10 +20,14 @@ import android.app.backup.BackupManager
import android.appwidget.AppWidgetProviderInfo
import android.content.ComponentName
import android.os.UserHandle
+import android.os.UserManager
import com.android.systemui.common.data.repository.PackageChangeRepository
import com.android.systemui.common.shared.model.PackageInstallSession
import com.android.systemui.communal.data.backup.CommunalBackupUtils
import com.android.systemui.communal.data.db.CommunalWidgetDao
+import com.android.systemui.communal.data.db.CommunalWidgetItem
+import com.android.systemui.communal.data.db.DefaultWidgetPopulation
+import com.android.systemui.communal.data.db.DefaultWidgetPopulation.SkipReason.RESTORED_FROM_BACKUP
import com.android.systemui.communal.nano.CommunalHubState
import com.android.systemui.communal.proto.toCommunalHubState
import com.android.systemui.communal.shared.model.CommunalWidgetContentModel
@@ -98,6 +102,8 @@ constructor(
private val backupManager: BackupManager,
private val backupUtils: CommunalBackupUtils,
packageChangeRepository: PackageChangeRepository,
+ private val userManager: UserManager,
+ private val defaultWidgetPopulation: DefaultWidgetPopulation,
) : CommunalWidgetRepository {
companion object {
const val TAG = "CommunalWidgetRepository"
@@ -185,6 +191,7 @@ constructor(
widgetId = id,
provider = provider,
priority = priority,
+ userSerialNumber = userManager.getUserSerialNumber(user.identifier),
)
backupManager.dataChanged()
} else {
@@ -228,9 +235,38 @@ constructor(
return@launch
}
+ // Abort restoring widgets if this code is somehow run on a device that does not have
+ // a main user, e.g. auto.
+ val mainUser = userManager.mainUser
+ if (mainUser == null) {
+ logger.w("Skipped restoring widgets because device does not have a main user")
+ return@launch
+ }
+
val widgetsWithHost = appWidgetHost.appWidgetIds.toList()
val widgetsToRemove = widgetsWithHost.toMutableList()
+ val oldUserSerialNumbers = state.widgets.map { it.userSerialNumber }.distinct()
+ val usersMap =
+ oldUserSerialNumbers.associateWith { oldUserSerialNumber ->
+ if (oldUserSerialNumber == CommunalWidgetItem.USER_SERIAL_NUMBER_UNDEFINED) {
+ // If user serial number from the backup is undefined, the widget was added
+ // to the hub before user serial numbers are stored in the database. In this
+ // case, we restore the widget with the main user.
+ mainUser
+ } else {
+ // If the user serial number is defined, look up whether the user is
+ // restored. This API returns a user handle matching its backed up user
+ // serial number, if the user is restored. Otherwise, null is returned.
+ backupManager.getUserForAncestralSerialNumber(oldUserSerialNumber.toLong())
+ ?: null
+ }
+ }
+ logger.d({ "Restored users map: $str1" }) { str1 = usersMap.toString() }
+
+ // A set to hold all widgets that belong to non-main users
+ val secondaryUserWidgets = mutableSetOf<CommunalHubState.CommunalWidgetItem>()
+
// Produce a new state to be restored, skipping invalid widgets
val newWidgets =
state.widgets.mapNotNull { restoredWidget ->
@@ -249,20 +285,67 @@ constructor(
return@mapNotNull null
}
+ // Skip if user / profile is not registered
+ val newUser = usersMap[restoredWidget.userSerialNumber]
+ if (newUser == null) {
+ logger.d({
+ "Skipped restoring widget $int1 because its user $int2 is not " +
+ "registered"
+ }) {
+ int1 = restoredWidget.widgetId
+ int2 = restoredWidget.userSerialNumber
+ }
+ return@mapNotNull null
+ }
+
+ // Place secondary user widgets in a bucket to be manually bound later because
+ // of a platform bug (b/349852237) that backs up work profile widgets as
+ // personal.
+ if (newUser.identifier != mainUser.identifier) {
+ logger.d({
+ "Skipped restoring widget $int1 for now because its new user $int2 " +
+ "is secondary. This widget will be bound later."
+ }) {
+ int1 = restoredWidget.widgetId
+ int2 = newUser.identifier
+ }
+ secondaryUserWidgets.add(restoredWidget)
+ return@mapNotNull null
+ }
+
widgetsToRemove.remove(newWidgetId)
CommunalHubState.CommunalWidgetItem().apply {
widgetId = newWidgetId
componentName = restoredWidget.componentName
rank = restoredWidget.rank
+ userSerialNumber = userManager.getUserSerialNumber(newUser.identifier)
}
}
val newState = CommunalHubState().apply { widgets = newWidgets.toTypedArray() }
+ // Skip default widgets population
+ defaultWidgetPopulation.skipDefaultWidgetsPopulation(RESTORED_FROM_BACKUP)
+
// Restore database
- logger.i("Restoring communal database $newState")
+ logger.i("Restoring communal database:\n$newState")
communalWidgetDao.restoreCommunalHubState(newState)
+ // Manually bind each secondary user widget due to platform bug b/349852237
+ secondaryUserWidgets.forEach { widget ->
+ val newUser = usersMap[widget.userSerialNumber]!!
+ logger.i({ "Binding secondary user ($int1) widget $int2: $str1" }) {
+ int1 = newUser.identifier
+ int2 = widget.widgetId
+ str1 = widget.componentName
+ }
+ addWidget(
+ provider = ComponentName.unflattenFromString(widget.componentName)!!,
+ user = newUser,
+ priority = widget.rank,
+ )
+ }
+
// Delete restored state file from disk
backupUtils.clear()
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 f5255ac4d545..3fffd76ab6a9 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
@@ -16,10 +16,10 @@
package com.android.systemui.communal.domain.interactor
-import android.app.smartspace.SmartspaceTarget
import android.content.ComponentName
import android.content.Intent
import android.content.IntentFilter
+import android.content.pm.UserInfo
import android.os.UserHandle
import android.os.UserManager
import android.provider.Settings
@@ -28,6 +28,7 @@ import com.android.compose.animation.scene.SceneKey
import com.android.compose.animation.scene.TransitionKey
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.communal.data.repository.CommunalMediaRepository
+import com.android.systemui.communal.data.repository.CommunalSmartspaceRepository
import com.android.systemui.communal.data.repository.CommunalWidgetRepository
import com.android.systemui.communal.domain.model.CommunalContentModel
import com.android.systemui.communal.domain.model.CommunalContentModel.WidgetContent
@@ -59,7 +60,6 @@ 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.settings.UserTracker
-import com.android.systemui.smartspace.data.repository.SmartspaceRepository
import com.android.systemui.util.kotlin.BooleanFlowOperators.allOf
import com.android.systemui.util.kotlin.BooleanFlowOperators.not
import com.android.systemui.util.kotlin.emitOnStart
@@ -81,7 +81,6 @@ import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flow
-import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
@@ -100,7 +99,7 @@ constructor(
private val widgetRepository: CommunalWidgetRepository,
private val communalPrefsInteractor: CommunalPrefsInteractor,
private val mediaRepository: CommunalMediaRepository,
- smartspaceRepository: SmartspaceRepository,
+ private val smartspaceRepository: CommunalSmartspaceRepository,
keyguardInteractor: KeyguardInteractor,
keyguardTransitionInteractor: KeyguardTransitionInteractor,
communalSettingsInteractor: CommunalSettingsInteractor,
@@ -386,11 +385,11 @@ constructor(
combine(
widgetRepository.communalWidgets
.map { filterWidgetsByExistingUsers(it) }
- .combine(communalSettingsInteractor.allowedByDevicePolicyForWorkProfile) {
+ .combine(communalSettingsInteractor.workProfileUserDisallowedByDevicePolicy) {
// exclude widgets under work profile if not allowed by device policy
widgets,
- allowedForWorkProfile ->
- filterWidgetsAllowedByDevicePolicy(widgets, allowedForWorkProfile)
+ disallowedByPolicyUser ->
+ filterWidgetsAllowedByDevicePolicy(widgets, disallowedByPolicyUser)
},
updateOnWorkProfileBroadcastReceived,
) { widgets, _ ->
@@ -418,13 +417,11 @@ constructor(
/** Filter widgets based on whether their associated profile is allowed by device policy. */
private fun filterWidgetsAllowedByDevicePolicy(
list: List<CommunalWidgetContentModel>,
- allowedByDevicePolicyForWorkProfile: Boolean
+ disallowedByDevicePolicyUser: UserInfo?
): List<CommunalWidgetContentModel> =
- if (allowedByDevicePolicyForWorkProfile) {
+ if (disallowedByDevicePolicyUser == null) {
list
} else {
- // Get associated work profile for the currently selected user.
- val workProfile = userTracker.userProfiles.find { it.isManagedProfile }
list.filter { model ->
val uid =
when (model) {
@@ -432,20 +429,7 @@ constructor(
model.providerInfo.profile.identifier
is CommunalWidgetContentModel.Pending -> model.user.identifier
}
- uid != workProfile?.id
- }
- }
-
- /** A flow of available smartspace targets. Currently only showing timers. */
- private val smartspaceTargets: Flow<List<SmartspaceTarget>> =
- if (!smartspaceRepository.isSmartspaceRemoteViewsEnabled) {
- flowOf(emptyList())
- } else {
- smartspaceRepository.communalSmartspaceTargets.map { targets ->
- targets.filter { target ->
- target.featureType == SmartspaceTarget.FEATURE_TIMER &&
- target.remoteViews != null
- }
+ uid != disallowedByDevicePolicyUser.id
}
}
@@ -473,16 +457,16 @@ constructor(
* sized dynamically.
*/
fun getOngoingContent(mediaHostVisible: Boolean): Flow<List<CommunalContentModel.Ongoing>> =
- combine(smartspaceTargets, mediaRepository.mediaModel) { smartspace, media ->
+ combine(smartspaceRepository.timers, mediaRepository.mediaModel) { timers, media ->
val ongoingContent = mutableListOf<CommunalContentModel.Ongoing>()
- // Add smartspace
+ // Add smartspace timers
ongoingContent.addAll(
- smartspace.map { target ->
+ timers.map { timer ->
CommunalContentModel.Smartspace(
- smartspaceTargetId = target.smartspaceTargetId,
- remoteViews = target.remoteViews!!,
- createdTimestampMillis = target.creationTimeMillis,
+ smartspaceTargetId = timer.smartspaceTargetId,
+ remoteViews = timer.remoteViews,
+ createdTimestampMillis = timer.createdTimestampMillis,
)
}
)
@@ -557,4 +541,29 @@ constructor(
)
}
}
+
+ /**
+ * {@link #setScrollPosition} persists the current communal grid scroll position (to volatile
+ * memory) so that the next presentation of the grid (either as glanceable hub or edit mode) can
+ * restore position.
+ */
+ fun setScrollPosition(firstVisibleItemIndex: Int, firstVisibleItemOffset: Int) {
+ _firstVisibleItemIndex = firstVisibleItemIndex
+ _firstVisibleItemOffset = firstVisibleItemOffset
+ }
+
+ fun resetScrollPosition() {
+ _firstVisibleItemIndex = 0
+ _firstVisibleItemOffset = 0
+ }
+
+ val firstVisibleItemIndex: Int
+ get() = _firstVisibleItemIndex
+
+ private var _firstVisibleItemIndex: Int = 0
+
+ val firstVisibleItemOffset: Int
+ get() = _firstVisibleItemOffset
+
+ private var _firstVisibleItemOffset: Int = 0
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractor.kt
index 47b75c458d20..3b01aec6861d 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractor.kt
@@ -92,15 +92,22 @@ constructor(
awaitClose { userTracker.removeCallback(callback) }
}
- /** Whether or not keyguard widgets are allowed for work profile by device policy manager. */
- val allowedByDevicePolicyForWorkProfile: StateFlow<Boolean> =
+ /**
+ * A user that device policy says shouldn't allow communal widgets, or null if there are no
+ * restrictions.
+ */
+ val workProfileUserDisallowedByDevicePolicy: StateFlow<UserInfo?> =
workProfileUserInfoCallbackFlow
.flatMapLatest { workProfile ->
- workProfile?.let { repository.getAllowedByDevicePolicy(it) } ?: flowOf(false)
+ workProfile?.let {
+ repository.getAllowedByDevicePolicy(it).map { allowed ->
+ if (!allowed) it else null
+ }
+ } ?: flowOf(null)
}
.stateIn(
scope = bgScope,
started = SharingStarted.WhileSubscribed(),
- initialValue = false
+ initialValue = null
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/proto/communal_hub_state.proto b/packages/SystemUI/src/com/android/systemui/communal/proto/communal_hub_state.proto
index 08162593b4d5..bc14ae1eaff4 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/proto/communal_hub_state.proto
+++ b/packages/SystemUI/src/com/android/systemui/communal/proto/communal_hub_state.proto
@@ -35,5 +35,8 @@ message CommunalHubState {
// Rank or order of the widget in the communal hub.
int32 rank = 3;
+
+ // Serial number of the user associated with the widget.
+ int32 user_serial_number = 4;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt
index 6ec6ec1113a0..19d7ceba2310 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt
@@ -59,6 +59,18 @@ abstract class BaseCommunalViewModel(
/** Accessibility delegate to be set on CommunalAppWidgetHostView. */
open val widgetAccessibilityDelegate: View.AccessibilityDelegate? = null
+ /**
+ * The up-to-date value of the grid scroll offset. persisted to interactor on
+ * {@link #persistScrollPosition}
+ */
+ private var currentScrollOffset = 0
+
+ /**
+ * The up-to-date value of the grid scroll index. persisted to interactor on
+ * {@link #persistScrollPosition}
+ */
+ private var currentScrollIndex = 0
+
fun signalUserInteraction() {
communalInteractor.signalUserInteraction()
}
@@ -147,6 +159,28 @@ abstract class BaseCommunalViewModel(
/** Called as the user request to show the customize widget button. */
open fun onLongClick() {}
+ /** Called when the grid scroll position has been updated. */
+ open fun onScrollPositionUpdated(firstVisibleItemIndex: Int, firstVisibleItemScroll: Int) {
+ currentScrollIndex = firstVisibleItemIndex
+ currentScrollOffset = firstVisibleItemScroll
+ }
+
+ /** Stores scroll values to interactor. */
+ protected fun persistScrollPosition() {
+ communalInteractor.setScrollPosition(currentScrollIndex, currentScrollOffset)
+ }
+
+ /** Invoked after scroll values are used to initialize grid position. */
+ open fun clearPersistedScrollPosition() {
+ communalInteractor.setScrollPosition(0, 0)
+ }
+
+ val savedFirstScrollIndex: Int
+ get() = communalInteractor.firstVisibleItemIndex
+
+ val savedFirstScrollOffset: Int
+ get() = communalInteractor.firstVisibleItemOffset
+
/** Set the key of the currently selected item */
fun setSelectedKey(key: String?) {
_selectedKey.value = key
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt
index 4f54fee3f498..7b0aadfdcebd 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt
@@ -43,6 +43,7 @@ import com.android.systemui.log.dagger.CommunalLog
import com.android.systemui.media.controls.ui.view.MediaHost
import com.android.systemui.media.dagger.MediaModule
import com.android.systemui.res.R
+import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.util.kotlin.BooleanFlowOperators.allOf
import com.android.systemui.util.kotlin.BooleanFlowOperators.not
import javax.inject.Inject
@@ -93,7 +94,10 @@ constructor(
*/
val canShowEditMode =
allOf(
- keyguardTransitionInteractor.isFinishedIn(KeyguardState.GONE),
+ keyguardTransitionInteractor.isFinishedIn(
+ scene = Scenes.Gone,
+ stateWithoutSceneContainer = KeyguardState.GONE
+ ),
communalInteractor.editModeOpen
)
.filter { it }
@@ -186,6 +190,10 @@ constructor(
AppWidgetManager.EXTRA_CATEGORY_FILTER,
CommunalWidgetCategories.defaultCategories
)
+
+ communalSettingsInteractor.workProfileUserDisallowedByDevicePolicy.value?.let {
+ putExtra(EXTRA_USER_ID_FILTER, arrayListOf(it.id))
+ }
putExtra(EXTRA_UI_SURFACE_KEY, EXTRA_UI_SURFACE_VALUE)
putExtra(EXTRA_PICKER_TITLE, resources.getString(R.string.communal_widget_picker_title))
putExtra(
@@ -212,6 +220,9 @@ constructor(
/** Called when exiting the edit mode, before transitioning back to the communal scene. */
fun cleanupEditModeState() {
communalSceneInteractor.setEditModeState(null)
+
+ // Set the scroll position of the glanceable hub to match where we are now.
+ persistScrollPosition()
}
companion object {
@@ -223,6 +234,7 @@ constructor(
private const val EXTRA_PICKER_DESCRIPTION = "picker_description"
private const val EXTRA_UI_SURFACE_KEY = "ui_surface"
private const val EXTRA_UI_SURFACE_VALUE = "widgets_hub"
+ private const val EXTRA_USER_ID_FILTER = "filtered_user_ids"
const val EXTRA_ADDED_APP_WIDGETS_KEY = "added_app_widgets"
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
index 780bf70f3f7b..02ecfe1b0cf9 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
@@ -233,7 +233,10 @@ constructor(
override fun onOpenWidgetEditor(
shouldOpenWidgetPickerOnStart: Boolean,
- ) = communalInteractor.showWidgetEditor(selectedKey.value, shouldOpenWidgetPickerOnStart)
+ ) {
+ persistScrollPosition()
+ communalInteractor.showWidgetEditor(selectedKey.value, shouldOpenWidgetPickerOnStart)
+ }
override fun onDismissCtaTile() {
scope.launch {
diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalWidgetModule.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalWidgetModule.kt
index 2000f96bcdb0..684303ae73cc 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalWidgetModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalWidgetModule.kt
@@ -43,12 +43,6 @@ interface CommunalWidgetModule {
@SysUISingleton
@Provides
- fun provideAppWidgetManager(@Application context: Context): Optional<AppWidgetManager> {
- return Optional.ofNullable(AppWidgetManager.getInstance(context))
- }
-
- @SysUISingleton
- @Provides
fun provideCommunalAppWidgetHost(
@Application context: Context,
@Background backgroundScope: CoroutineScope,
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
index b0fc60e74b52..2ea27b76d81b 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
@@ -16,6 +16,9 @@
package com.android.systemui.dagger;
+import static com.android.systemui.Flags.enableViewCaptureTracing;
+import static com.android.systemui.util.ConvenienceExtensionsKt.toKotlinLazy;
+
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.app.ActivityManager;
@@ -39,6 +42,7 @@ import android.app.job.JobScheduler;
import android.app.role.RoleManager;
import android.app.smartspace.SmartspaceManager;
import android.app.trust.TrustManager;
+import android.appwidget.AppWidgetManager;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothManager;
import android.companion.virtual.VirtualDeviceManager;
@@ -111,6 +115,9 @@ import android.view.textclassifier.TextClassificationManager;
import androidx.asynclayoutinflater.view.AsyncLayoutInflater;
import androidx.core.app.NotificationManagerCompat;
+import com.android.app.viewcapture.ViewCapture;
+import com.android.app.viewcapture.ViewCaptureAwareWindowManager;
+import com.android.app.viewcapture.ViewCaptureFactory;
import com.android.internal.app.IBatteryStats;
import com.android.internal.appwidget.IAppWidgetService;
import com.android.internal.jank.InteractionJankMonitor;
@@ -125,6 +132,7 @@ import com.android.systemui.shared.system.PackageManagerWrapper;
import com.android.systemui.user.utils.UserScopedService;
import com.android.systemui.user.utils.UserScopedServiceImpl;
+import dagger.Lazy;
import dagger.Module;
import dagger.Provides;
@@ -367,6 +375,12 @@ public class FrameworkServicesModule {
@Provides
@Singleton
+ static Optional<AppWidgetManager> provideAppWidgetManager(@Application Context context) {
+ return Optional.ofNullable(AppWidgetManager.getInstance(context));
+ }
+
+ @Provides
+ @Singleton
static IAppWidgetService provideIAppWidgetService() {
return IAppWidgetService.Stub.asInterface(
ServiceManager.getService(Context.APPWIDGET_SERVICE));
@@ -680,6 +694,15 @@ public class FrameworkServicesModule {
@Provides
@Singleton
+ static ViewCaptureAwareWindowManager provideViewCaptureAwareWindowManager(
+ WindowManager windowManager, Lazy<ViewCapture> daggerLazyViewCapture) {
+ return new ViewCaptureAwareWindowManager(windowManager,
+ /* lazyViewCapture= */ toKotlinLazy(daggerLazyViewCapture),
+ /* isViewCaptureEnabled= */ enableViewCaptureTracing());
+ }
+
+ @Provides
+ @Singleton
static PermissionManager providePermissionManager(Context context) {
PermissionManager pm = context.getSystemService(PermissionManager.class);
if (pm != null) {
@@ -764,4 +787,10 @@ public class FrameworkServicesModule {
return IDeviceIdleController.Stub.asInterface(
ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER));
}
+
+ @Provides
+ @Singleton
+ static ViewCapture provideViewCapture(Context context) {
+ return ViewCaptureFactory.getInstance(context);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
index 593196c54dae..88601dab891d 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
@@ -24,11 +24,6 @@ import com.android.systemui.accessibility.Magnification
import com.android.systemui.back.domain.interactor.BackActionInteractor
import com.android.systemui.biometrics.BiometricNotificationService
import com.android.systemui.clipboardoverlay.ClipboardListener
-import com.android.systemui.communal.CommunalDreamStartable
-import com.android.systemui.communal.CommunalBackupRestoreStartable
-import com.android.systemui.communal.CommunalSceneStartable
-import com.android.systemui.communal.log.CommunalLoggerStartable
-import com.android.systemui.communal.widgets.CommunalAppWidgetHostStartable
import com.android.systemui.controls.dagger.StartControlsStartableModule
import com.android.systemui.dagger.qualifiers.PerUser
import com.android.systemui.dreams.AssistantAttentionMonitor
@@ -80,12 +75,13 @@ import dagger.multibindings.IntoMap
* @deprecated
*/
@Module(
- includes = [
- MultiUserUtilsModule::class,
- StartControlsStartableModule::class,
- StartBinderLoggerModule::class,
- WallpaperModule::class,
- ]
+ includes =
+ [
+ MultiUserUtilsModule::class,
+ StartControlsStartableModule::class,
+ StartBinderLoggerModule::class,
+ WallpaperModule::class,
+ ]
)
abstract class SystemUICoreStartableModule {
/** Inject into BiometricNotificationService */
@@ -96,25 +92,25 @@ abstract class SystemUICoreStartableModule {
service: BiometricNotificationService
): CoreStartable
- /** Inject into ClipboardListener. */
+ /** Inject into ClipboardListener. */
@Binds
@IntoMap
@ClassKey(ClipboardListener::class)
abstract fun bindClipboardListener(sysui: ClipboardListener): CoreStartable
- /** Inject into GlobalActionsComponent. */
+ /** Inject into GlobalActionsComponent. */
@Binds
@IntoMap
@ClassKey(GlobalActionsComponent::class)
abstract fun bindGlobalActionsComponent(sysui: GlobalActionsComponent): CoreStartable
- /** Inject into InstantAppNotifier. */
+ /** Inject into InstantAppNotifier. */
@Binds
@IntoMap
@ClassKey(InstantAppNotifier::class)
abstract fun bindInstantAppNotifier(sysui: InstantAppNotifier): CoreStartable
- /** Inject into KeyboardUI. */
+ /** Inject into KeyboardUI. */
@Binds
@IntoMap
@ClassKey(KeyboardUI::class)
@@ -125,7 +121,7 @@ abstract class SystemUICoreStartableModule {
@IntoMap
@ClassKey(MediaProjectionTaskSwitcherCoreStartable::class)
abstract fun bindProjectedTaskListener(
- sysui: MediaProjectionTaskSwitcherCoreStartable
+ sysui: MediaProjectionTaskSwitcherCoreStartable
): CoreStartable
/** Inject into KeyguardBiometricLockoutLogger */
@@ -136,38 +132,38 @@ abstract class SystemUICoreStartableModule {
sysui: KeyguardBiometricLockoutLogger
): CoreStartable
- /** Inject into KeyguardViewMediator. */
+ /** Inject into KeyguardViewMediator. */
@Binds
@IntoMap
@ClassKey(KeyguardViewMediator::class)
abstract fun bindKeyguardViewMediator(sysui: KeyguardViewMediator): CoreStartable
- /** Inject into LatencyTests. */
+ /** Inject into LatencyTests. */
@Binds
@IntoMap
@ClassKey(LatencyTester::class)
abstract fun bindLatencyTester(sysui: LatencyTester): CoreStartable
- /** Inject into DisplaySwitchLatencyTracker. */
+ /** Inject into DisplaySwitchLatencyTracker. */
@Binds
@IntoMap
@ClassKey(DisplaySwitchLatencyTracker::class)
abstract fun bindDisplaySwitchLatencyTracker(sysui: DisplaySwitchLatencyTracker): CoreStartable
- /** Inject into NotificationChannels. */
+ /** Inject into NotificationChannels. */
@Binds
@IntoMap
@ClassKey(NotificationChannels::class)
@PerUser
abstract fun bindNotificationChannels(sysui: NotificationChannels): CoreStartable
- /** Inject into ImmersiveModeConfirmation. */
+ /** Inject into ImmersiveModeConfirmation. */
@Binds
@IntoMap
@ClassKey(ImmersiveModeConfirmation::class)
abstract fun bindImmersiveModeConfirmation(sysui: ImmersiveModeConfirmation): CoreStartable
- /** Inject into RingtonePlayer. */
+ /** Inject into RingtonePlayer. */
@Binds
@IntoMap
@ClassKey(RingtonePlayer::class)
@@ -179,50 +175,49 @@ abstract class SystemUICoreStartableModule {
@ClassKey(GesturePointerEventListener::class)
abstract fun bindGesturePointerEventListener(sysui: GesturePointerEventListener): CoreStartable
- /** Inject into SessionTracker. */
+ /** Inject into SessionTracker. */
@Binds
@IntoMap
@ClassKey(SessionTracker::class)
abstract fun bindSessionTracker(service: SessionTracker): CoreStartable
- /** Inject into ShortcutKeyDispatcher. */
+ /** Inject into ShortcutKeyDispatcher. */
@Binds
@IntoMap
@ClassKey(ShortcutKeyDispatcher::class)
abstract fun bindShortcutKeyDispatcher(sysui: ShortcutKeyDispatcher): CoreStartable
- /** Inject into SliceBroadcastRelayHandler. */
+ /** Inject into SliceBroadcastRelayHandler. */
@Binds
@IntoMap
@ClassKey(SliceBroadcastRelayHandler::class)
abstract fun bindSliceBroadcastRelayHandler(sysui: SliceBroadcastRelayHandler): CoreStartable
- /** Inject into StorageNotification. */
+ /** Inject into StorageNotification. */
@Binds
@IntoMap
@ClassKey(StorageNotification::class)
abstract fun bindStorageNotification(sysui: StorageNotification): CoreStartable
- /** Inject into ThemeOverlayController. */
+ /** Inject into ThemeOverlayController. */
@Binds
@IntoMap
@ClassKey(ThemeOverlayController::class)
abstract fun bindThemeOverlayController(sysui: ThemeOverlayController): CoreStartable
-
- /** Inject into MediaOutputSwitcherDialogUI. */
+ /** Inject into MediaOutputSwitcherDialogUI. */
@Binds
@IntoMap
@ClassKey(MediaOutputSwitcherDialogUI::class)
abstract fun MediaOutputSwitcherDialogUI(sysui: MediaOutputSwitcherDialogUI): CoreStartable
- /** Inject into Magnification. */
+ /** Inject into Magnification. */
@Binds
@IntoMap
@ClassKey(Magnification::class)
abstract fun bindMagnification(sysui: Magnification): CoreStartable
- /** Inject into WMShell. */
+ /** Inject into WMShell. */
@Binds
@IntoMap
@ClassKey(WMShell::class)
@@ -239,7 +234,7 @@ abstract class SystemUICoreStartableModule {
@IntoMap
@ClassKey(MediaTttChipControllerReceiver::class)
abstract fun bindMediaTttChipControllerReceiver(
- sysui: MediaTttChipControllerReceiver
+ sysui: MediaTttChipControllerReceiver
): CoreStartable
/** Inject into MediaTttCommandLineHelper. */
@@ -254,8 +249,6 @@ abstract class SystemUICoreStartableModule {
@ClassKey(ChipbarCoordinator::class)
abstract fun bindChipbarController(sysui: ChipbarCoordinator): CoreStartable
-
-
/** Inject into StylusUsiPowerStartable) */
@Binds
@IntoMap
@@ -267,21 +260,21 @@ abstract class SystemUICoreStartableModule {
@ClassKey(PhysicalKeyboardCoreStartable::class)
abstract fun bindKeyboardCoreStartable(listener: PhysicalKeyboardCoreStartable): CoreStartable
- /** Inject into MuteQuickAffordanceCoreStartable*/
+ /** Inject into MuteQuickAffordanceCoreStartable */
@Binds
@IntoMap
@ClassKey(MuteQuickAffordanceCoreStartable::class)
abstract fun bindMuteQuickAffordanceCoreStartable(
- sysui: MuteQuickAffordanceCoreStartable
+ sysui: MuteQuickAffordanceCoreStartable
): CoreStartable
- /**Inject into DreamMonitor */
+ /** Inject into DreamMonitor */
@Binds
@IntoMap
@ClassKey(DreamMonitor::class)
abstract fun bindDreamMonitor(sysui: DreamMonitor): CoreStartable
- /**Inject into AssistantAttentionMonitor */
+ /** Inject into AssistantAttentionMonitor */
@Binds
@IntoMap
@ClassKey(AssistantAttentionMonitor::class)
@@ -321,35 +314,6 @@ abstract class SystemUICoreStartableModule {
@Binds
@IntoMap
- @ClassKey(CommunalLoggerStartable::class)
- abstract fun bindCommunalLoggerStartable(impl: CommunalLoggerStartable): CoreStartable
-
- @Binds
- @IntoMap
- @ClassKey(CommunalSceneStartable::class)
- abstract fun bindCommunalSceneStartable(impl: CommunalSceneStartable): CoreStartable
-
- @Binds
- @IntoMap
- @ClassKey(CommunalDreamStartable::class)
- abstract fun bindCommunalDreamStartable(impl: CommunalDreamStartable): CoreStartable
-
- @Binds
- @IntoMap
- @ClassKey(CommunalAppWidgetHostStartable::class)
- abstract fun bindCommunalAppWidgetHostStartable(
- impl: CommunalAppWidgetHostStartable
- ): CoreStartable
-
- @Binds
- @IntoMap
- @ClassKey(CommunalBackupRestoreStartable::class)
- abstract fun bindCommunalBackupRestoreStartable(
- impl: CommunalBackupRestoreStartable
- ): CoreStartable
-
- @Binds
- @IntoMap
@ClassKey(HomeControlsDreamStartable::class)
abstract fun bindHomeControlsDreamStartable(impl: HomeControlsDreamStartable): CoreStartable
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 ed30d59a94fa..fa52dad17966 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
@@ -303,7 +303,10 @@ constructor(
private fun listenForSchedulingWatchdog() {
keyguardTransitionInteractor
- .transition(Edge.create(to = KeyguardState.GONE))
+ .transition(
+ edge = Edge.create(to = Scenes.Gone),
+ edgeWithoutSceneContainer = Edge.create(to = KeyguardState.GONE),
+ )
.filter { it.transitionState == TransitionState.FINISHED }
.onEach {
// We deliberately want to run this in background because scheduleWatchdog does
@@ -324,7 +327,7 @@ constructor(
combine(
keyguardTransitionInteractor.isFinishedIn(
scene = Scenes.Gone,
- stateWithoutSceneContainer = KeyguardState.GONE
+ stateWithoutSceneContainer = KeyguardState.GONE,
),
keyguardInteractor.statusBarState,
) { isFinishedInGoneState, statusBarState ->
diff --git a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt
index 0bcfa9616b76..69ddb62cc05a 100644
--- a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt
@@ -44,6 +44,7 @@ import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.filterIsInstance
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
@@ -137,6 +138,7 @@ constructor(
override val displayAdditionEvent: Flow<Display?> =
allDisplayEvents.filterIsInstance<DisplayEvent.Added>().map { getDisplay(it.displayId) }
+ // TODO: b/345472038 - Delete after the flag is ramped up.
private val oldEnabledDisplays: Flow<Set<Display>> =
allDisplayEvents
.map { getDisplays() }
@@ -167,6 +169,9 @@ constructor(
}
.debugLog("enabledDisplayIds")
+ private val defaultDisplay by lazy {
+ getDisplay(Display.DEFAULT_DISPLAY) ?: error("Unable to get default display.")
+ }
/**
* Represents displays that went though the [DisplayListener.onDisplayAdded] callback.
*
@@ -181,11 +186,7 @@ constructor(
.stateIn(
bgApplicationScope,
started = SharingStarted.WhileSubscribed(),
- initialValue =
- setOf(
- getDisplay(Display.DEFAULT_DISPLAY)
- ?: error("Unable to get default display.")
- )
+ initialValue = setOf(defaultDisplay)
)
} else {
oldEnabledDisplays
@@ -344,9 +345,10 @@ constructor(
.debugLog("pendingDisplay")
override val defaultDisplayOff: Flow<Boolean> =
- displays
- .map { displays -> displays.firstOrNull { it.displayId == Display.DEFAULT_DISPLAY } }
- .map { it?.state == Display.STATE_OFF }
+ displayChangeEvent
+ .filter { it == Display.DEFAULT_DISPLAY }
+ .map { defaultDisplay.state == Display.STATE_OFF }
+ .distinctUntilChanged()
private fun <T> Flow<T>.debugLog(flowName: String): Flow<T> {
return if (DEBUG) {
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
index 8776ec5496c8..17b455d7ef6f 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
@@ -18,6 +18,8 @@ package com.android.systemui.doze;
import android.annotation.NonNull;
+import androidx.annotation.MainThread;
+
/**
* Interface the doze service uses to communicate with the rest of system UI.
*/
@@ -27,6 +29,7 @@ public interface DozeHost {
void startDozing();
void pulseWhileDozing(@NonNull PulseCallback callback, int reason);
void stopDozing();
+ @MainThread
void dozeTimeTick();
boolean isPowerSaveActive();
boolean isPulsingBlocked();
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
index 1a06418065a2..9def81a89e3a 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
@@ -27,6 +27,8 @@ import android.os.SystemClock;
import android.text.format.Formatter;
import android.util.Log;
+import androidx.annotation.AnyThread;
+
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.doze.dagger.DozeScope;
@@ -55,7 +57,7 @@ public class DozeUi implements DozeMachine.Part {
private final DozeParameters mDozeParameters;
private final DozeLog mDozeLog;
private final DelayableExecutor mBgExecutor;
- private long mLastTimeTickElapsed = 0;
+ private volatile long mLastTimeTickElapsed = 0;
// If time tick is scheduled and there's not a pending runnable to cancel:
private volatile boolean mTimeTickScheduled;
private final Runnable mCancelTimeTickerRunnable = new Runnable() {
@@ -218,10 +220,15 @@ public class DozeUi implements DozeMachine.Part {
return calendar.getTimeInMillis();
}
+ @AnyThread
private void onTimeTick() {
verifyLastTimeTick();
- mHost.dozeTimeTick();
+ if (dozeuiSchedulingAlarmsBackgroundExecution()) {
+ mHandler.post(mHost::dozeTimeTick);
+ } else {
+ mHost.dozeTimeTick();
+ }
// Keep wakelock until a frame has been pushed.
mHandler.post(mWakeLock.wrap(() -> {}));
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
index c6c5747973b3..83fa001d104e 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
@@ -45,6 +45,7 @@ import androidx.lifecycle.LifecycleService;
import androidx.lifecycle.ServiceLifecycleDispatcher;
import androidx.lifecycle.ViewModelStore;
+import com.android.app.viewcapture.ViewCaptureAwareWindowManager;
import com.android.dream.lowlight.dagger.LowLightDreamModule;
import com.android.internal.logging.UiEvent;
import com.android.internal.logging.UiEventLogger;
@@ -97,7 +98,7 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ
@Nullable
private final ComponentName mHomeControlPanelDreamComponent;
private final UiEventLogger mUiEventLogger;
- private final WindowManager mWindowManager;
+ private final ViewCaptureAwareWindowManager mWindowManager;
private final String mWindowTitle;
// A reference to the {@link Window} used to hold the dream overlay.
@@ -244,7 +245,7 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ
Context context,
DreamOverlayLifecycleOwner lifecycleOwner,
@Main DelayableExecutor executor,
- WindowManager windowManager,
+ ViewCaptureAwareWindowManager viewCaptureAwareWindowManager,
ComplicationComponent.Factory complicationComponentFactory,
com.android.systemui.dreams.complication.dagger.ComplicationComponent.Factory
dreamComplicationComponentFactory,
@@ -267,7 +268,7 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ
super(executor);
mContext = context;
mExecutor = executor;
- mWindowManager = windowManager;
+ mWindowManager = viewCaptureAwareWindowManager;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mScrimManager = scrimManager;
mLowLightDreamComponent = lowLightDreamComponent;
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/homecontrols/TaskFragmentComponent.kt b/packages/SystemUI/src/com/android/systemui/dreams/homecontrols/TaskFragmentComponent.kt
index 297ad847caa6..befd822e14cd 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/homecontrols/TaskFragmentComponent.kt
+++ b/packages/SystemUI/src/com/android/systemui/dreams/homecontrols/TaskFragmentComponent.kt
@@ -161,5 +161,6 @@ constructor(
TASK_FRAGMENT_TRANSIT_CLOSE,
false
)
+ organizer.unregisterOrganizer()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffect.kt b/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffect.kt
index 7b5139aa510e..c44eb471d460 100644
--- a/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffect.kt
+++ b/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffect.kt
@@ -17,8 +17,10 @@
package com.android.systemui.haptics.qs
import android.os.VibrationEffect
+import android.service.quicksettings.Tile
import androidx.annotation.VisibleForTesting
import com.android.systemui.animation.Expandable
+import com.android.systemui.plugins.FalsingManager
import com.android.systemui.plugins.qs.QSTile
import com.android.systemui.statusbar.VibratorHelper
import com.android.systemui.statusbar.policy.KeyguardStateController
@@ -40,6 +42,7 @@ class QSLongPressEffect
constructor(
private val vibratorHelper: VibratorHelper?,
private val keyguardStateController: KeyguardStateController,
+ private val falsingManager: FalsingManager,
) {
var effectDuration = 0
@@ -130,18 +133,18 @@ constructor(
fun handleAnimationComplete() {
when (state) {
State.RUNNING_FORWARD -> {
- setState(State.IDLE)
vibrate(snapEffect)
if (keyguardStateController.isUnlocked) {
- qsTile?.longClick(expandable)
+ setState(State.LONG_CLICKED)
} else {
callback?.onResetProperties()
- qsTile?.longClick(expandable)
+ setState(State.IDLE)
}
+ qsTile?.longClick(expandable)
}
State.RUNNING_BACKWARDS_FROM_UP -> {
- setState(State.IDLE)
callback?.onEffectFinishedReversing()
+ setState(getStateForClick())
qsTile?.click(expandable)
}
State.RUNNING_BACKWARDS_FROM_CANCEL -> setState(State.IDLE)
@@ -160,14 +163,37 @@ constructor(
}
fun onTileClick(): Boolean {
- if (state == State.TIMEOUT_WAIT) {
- setState(State.IDLE)
- qsTile?.let {
- it.click(expandable)
- return true
- }
+ val isStateClickable = state == State.TIMEOUT_WAIT || state == State.IDLE
+
+ // Ignore View-generated clicks on invalid states or if the bouncer is showing
+ if (keyguardStateController.isPrimaryBouncerShowing || !isStateClickable) return false
+
+ setState(getStateForClick())
+ qsTile?.click(expandable)
+ return true
+ }
+
+ /**
+ * Get the appropriate state for a click action.
+ *
+ * In some occasions, the click action will not result in a subsequent action that resets the
+ * state upon completion (e.g., a launch transition animation). In these cases, the state needs
+ * to be reset before the click is dispatched.
+ */
+ @VisibleForTesting
+ fun getStateForClick(): State {
+ val isTileUnavailable = qsTile?.state?.state == Tile.STATE_UNAVAILABLE
+ val isFalseTapWhileLocked =
+ !keyguardStateController.isUnlocked &&
+ falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)
+ val handlesLongClick = qsTile?.state?.handlesLongClick == true
+ return if (isTileUnavailable || isFalseTapWhileLocked || !handlesLongClick) {
+ // The click event will not perform an action that resets the state. Therefore, this is
+ // the last opportunity to reset the state back to IDLE.
+ State.IDLE
+ } else {
+ State.CLICKED
}
- return false
}
/**
@@ -194,6 +220,8 @@ constructor(
return true
}
+ fun resetState() = setState(State.IDLE)
+
enum class State {
IDLE, /* The effect is idle waiting for touch input */
TIMEOUT_WAIT, /* The effect is waiting for a tap timeout period */
@@ -202,6 +230,8 @@ constructor(
RUNNING_BACKWARDS_FROM_UP,
/* The effect was interrupted by an ACTION_CANCEL and is now running backwards */
RUNNING_BACKWARDS_FROM_CANCEL,
+ CLICKED, /* The effect has ended with a click */
+ LONG_CLICKED, /* The effect has ended with a long-click */
}
/** Callbacks to notify view and animator actions */
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ShortcutHelperModule.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ShortcutHelperModule.kt
index 1f0aef8ab977..906f600e3826 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ShortcutHelperModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ShortcutHelperModule.kt
@@ -21,11 +21,13 @@ import com.android.systemui.CoreStartable
import com.android.systemui.Flags.keyboardShortcutHelperRewrite
import com.android.systemui.keyboard.shortcut.data.repository.ShortcutHelperStateRepository
import com.android.systemui.keyboard.shortcut.data.source.AppCategoriesShortcutsSource
+import com.android.systemui.keyboard.shortcut.data.source.CurrentAppShortcutsSource
import com.android.systemui.keyboard.shortcut.data.source.InputShortcutsSource
import com.android.systemui.keyboard.shortcut.data.source.KeyboardShortcutGroupsSource
import com.android.systemui.keyboard.shortcut.data.source.MultitaskingShortcutsSource
import com.android.systemui.keyboard.shortcut.data.source.SystemShortcutsSource
import com.android.systemui.keyboard.shortcut.qualifiers.AppCategoriesShortcuts
+import com.android.systemui.keyboard.shortcut.qualifiers.CurrentAppShortcuts
import com.android.systemui.keyboard.shortcut.qualifiers.InputShortcuts
import com.android.systemui.keyboard.shortcut.qualifiers.MultitaskingShortcuts
import com.android.systemui.keyboard.shortcut.qualifiers.SystemShortcuts
@@ -55,6 +57,10 @@ interface ShortcutHelperModule {
fun multitaskingShortcutsSource(impl: MultitaskingShortcutsSource): KeyboardShortcutGroupsSource
@Binds
+ @CurrentAppShortcuts
+ fun currentAppShortcutsSource(impl: CurrentAppShortcutsSource): KeyboardShortcutGroupsSource
+
+ @Binds
@InputShortcuts
fun inputShortcutsSources(impl: InputShortcutsSource): KeyboardShortcutGroupsSource
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperCategoriesRepository.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperCategoriesRepository.kt
index 7b0c25e8379d..49817b263583 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperCategoriesRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperCategoriesRepository.kt
@@ -20,6 +20,7 @@ import android.content.Context
import android.graphics.drawable.Icon
import android.hardware.input.InputManager
import android.util.Log
+import android.view.InputDevice
import android.view.KeyCharacterMap
import android.view.KeyEvent
import android.view.KeyboardShortcutGroup
@@ -28,16 +29,18 @@ import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.keyboard.shortcut.data.source.KeyboardShortcutGroupsSource
import com.android.systemui.keyboard.shortcut.qualifiers.AppCategoriesShortcuts
+import com.android.systemui.keyboard.shortcut.qualifiers.CurrentAppShortcuts
import com.android.systemui.keyboard.shortcut.qualifiers.InputShortcuts
import com.android.systemui.keyboard.shortcut.qualifiers.MultitaskingShortcuts
import com.android.systemui.keyboard.shortcut.qualifiers.SystemShortcuts
import com.android.systemui.keyboard.shortcut.shared.model.Shortcut
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategory
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType
-import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.APP_CATEGORIES
-import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.IME
-import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.MULTI_TASKING
-import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.SYSTEM
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.AppCategories
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.CurrentApp
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.InputMethodEditor
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.MultiTasking
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.System
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCommand
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutHelperState.Active
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutIcon
@@ -45,7 +48,11 @@ import com.android.systemui.keyboard.shortcut.shared.model.ShortcutKey
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutSubCategory
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.withContext
@SysUISingleton
@@ -53,11 +60,13 @@ class ShortcutHelperCategoriesRepository
@Inject
constructor(
private val context: Context,
+ @Background private val backgroundScope: CoroutineScope,
@Background private val backgroundDispatcher: CoroutineDispatcher,
@SystemShortcuts private val systemShortcutsSource: KeyboardShortcutGroupsSource,
@MultitaskingShortcuts private val multitaskingShortcutsSource: KeyboardShortcutGroupsSource,
@AppCategoriesShortcuts private val appCategoriesShortcutsSource: KeyboardShortcutGroupsSource,
@InputShortcuts private val inputShortcutsSource: KeyboardShortcutGroupsSource,
+ @CurrentAppShortcuts private val currentAppShortcutsSource: KeyboardShortcutGroupsSource,
private val inputManager: InputManager,
stateRepository: ShortcutHelperStateRepository
) {
@@ -71,61 +80,82 @@ constructor(
}
}
- val systemShortcutsCategory =
- activeInputDevice.map {
- if (it != null) {
- toShortcutCategory(
- it.keyCharacterMap,
- SYSTEM,
- systemShortcutsSource.shortcutGroups(it.id),
- keepIcons = true,
+ val categories: Flow<List<ShortcutCategory>> =
+ activeInputDevice
+ .map {
+ if (it == null) {
+ return@map emptyList()
+ }
+ return@map listOfNotNull(
+ fetchSystemShortcuts(it),
+ fetchMultiTaskingShortcuts(it),
+ fetchAppCategoriesShortcuts(it),
+ fetchImeShortcuts(it),
+ fetchCurrentAppShortcuts(it),
)
- } else {
- null
}
- }
+ .stateIn(
+ scope = backgroundScope,
+ started = SharingStarted.Lazily,
+ initialValue = emptyList(),
+ )
- val multitaskingShortcutsCategory =
- activeInputDevice.map {
- if (it != null) {
- toShortcutCategory(
- it.keyCharacterMap,
- MULTI_TASKING,
- multitaskingShortcutsSource.shortcutGroups(it.id),
- keepIcons = true,
- )
- } else {
- null
- }
- }
+ private suspend fun fetchSystemShortcuts(inputDevice: InputDevice) =
+ toShortcutCategory(
+ inputDevice.keyCharacterMap,
+ System,
+ systemShortcutsSource.shortcutGroups(inputDevice.id),
+ keepIcons = true,
+ )
- val appCategoriesShortcutsCategory =
- activeInputDevice.map {
- if (it != null) {
- toShortcutCategory(
- it.keyCharacterMap,
- APP_CATEGORIES,
- appCategoriesShortcutsSource.shortcutGroups(it.id),
- keepIcons = true,
- )
- } else {
- null
- }
+ private suspend fun fetchMultiTaskingShortcuts(inputDevice: InputDevice) =
+ toShortcutCategory(
+ inputDevice.keyCharacterMap,
+ MultiTasking,
+ multitaskingShortcutsSource.shortcutGroups(inputDevice.id),
+ keepIcons = true,
+ )
+
+ private suspend fun fetchAppCategoriesShortcuts(inputDevice: InputDevice) =
+ toShortcutCategory(
+ inputDevice.keyCharacterMap,
+ AppCategories,
+ appCategoriesShortcutsSource.shortcutGroups(inputDevice.id),
+ keepIcons = true,
+ )
+
+ private suspend fun fetchImeShortcuts(inputDevice: InputDevice) =
+ toShortcutCategory(
+ inputDevice.keyCharacterMap,
+ InputMethodEditor,
+ inputShortcutsSource.shortcutGroups(inputDevice.id),
+ keepIcons = false,
+ )
+
+ private suspend fun fetchCurrentAppShortcuts(inputDevice: InputDevice): ShortcutCategory? {
+ val shortcutGroups = currentAppShortcutsSource.shortcutGroups(inputDevice.id)
+ val categoryType = getCurrentAppShortcutCategoryType(shortcutGroups)
+ return if (categoryType == null) {
+ null
+ } else {
+ toShortcutCategory(
+ inputDevice.keyCharacterMap,
+ categoryType,
+ shortcutGroups,
+ keepIcons = false
+ )
}
+ }
- val imeShortcutsCategory =
- activeInputDevice.map {
- if (it != null) {
- toShortcutCategory(
- it.keyCharacterMap,
- IME,
- inputShortcutsSource.shortcutGroups(it.id),
- keepIcons = false,
- )
- } else {
- null
- }
+ private fun getCurrentAppShortcutCategoryType(
+ shortcutGroups: List<KeyboardShortcutGroup>
+ ): ShortcutCategoryType? {
+ return if (shortcutGroups.isEmpty()) {
+ null
+ } else {
+ CurrentApp(packageName = shortcutGroups[0].packageName.toString())
}
+ }
private fun toShortcutCategory(
keyCharacterMap: KeyCharacterMap,
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperKeys.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperKeys.kt
index 0aced8c95662..cbe6fc7c6026 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperKeys.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperKeys.kt
@@ -222,7 +222,7 @@ object ShortcutHelperKeys {
{ context ->
context.getString(R.string.keyboard_key_forward_del)
},
- KEYCODE_ESCAPE to { "Esc" },
+ KEYCODE_ESCAPE to { context -> context.getString(R.string.keyboard_key_esc) },
KEYCODE_SYSRQ to { "SysRq" },
KEYCODE_BREAK to { "Break" },
KEYCODE_SCROLL_LOCK to { "Scroll Lock" },
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/CurrentAppShortcutsSource.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/CurrentAppShortcutsSource.kt
new file mode 100644
index 000000000000..7e6ed19d6070
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/CurrentAppShortcutsSource.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.keyboard.shortcut.data.source
+
+import android.view.KeyboardShortcutGroup
+import android.view.WindowManager
+import android.view.WindowManager.KeyboardShortcutsReceiver
+import javax.inject.Inject
+import kotlinx.coroutines.suspendCancellableCoroutine
+
+class CurrentAppShortcutsSource @Inject constructor(private val windowManager: WindowManager) :
+ KeyboardShortcutGroupsSource {
+ override suspend fun shortcutGroups(deviceId: Int): List<KeyboardShortcutGroup> =
+ suspendCancellableCoroutine { continuation ->
+ val shortcutsReceiver = KeyboardShortcutsReceiver {
+ continuation.resumeWith(Result.success(it ?: emptyList()))
+ }
+ windowManager.requestAppKeyboardShortcuts(shortcutsReceiver, deviceId)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/InputShortcutsSource.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/InputShortcutsSource.kt
index aba441546e35..1b2098650278 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/InputShortcutsSource.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/InputShortcutsSource.kt
@@ -59,7 +59,7 @@ constructor(@Main private val resources: Resources, private val windowManager: W
private suspend fun getImeShortcutGroup(deviceId: Int): List<KeyboardShortcutGroup> =
suspendCancellableCoroutine { continuation ->
val shortcutsReceiver = KeyboardShortcutsReceiver {
- continuation.resumeWith(Result.success(it))
+ continuation.resumeWith(Result.success(it ?: emptyList()))
}
windowManager.requestImeKeyboardShortcuts(shortcutsReceiver, deviceId)
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractor.kt
index d41d21a3b4fb..6f19561dd87b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractor.kt
@@ -23,7 +23,7 @@ import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategory
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutSubCategory
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.map
@SysUISingleton
class ShortcutHelperCategoriesInteractor
@@ -33,13 +33,8 @@ constructor(
) {
val shortcutCategories: Flow<List<ShortcutCategory>> =
- combine(
- categoriesRepository.systemShortcutsCategory,
- categoriesRepository.multitaskingShortcutsCategory,
- categoriesRepository.imeShortcutsCategory,
- categoriesRepository.appCategoriesShortcutsCategory,
- ) { shortcutCategories ->
- shortcutCategories.filterNotNull().map { groupSubCategoriesInCategory(it) }
+ categoriesRepository.categories.map { categories ->
+ categories.map { category -> groupSubCategoriesInCategory(category) }
}
private fun groupSubCategoriesInCategory(shortcutCategory: ShortcutCategory): ShortcutCategory {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/shared/model/IconLabelVisibilityLog.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/qualifiers/CurrentAppShortcuts.kt
index c92234c3e535..51631b11b27c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/shared/model/IconLabelVisibilityLog.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/qualifiers/CurrentAppShortcuts.kt
@@ -14,11 +14,8 @@
* limitations under the License.
*/
-package com.android.systemui.qs.panels.shared.model
+package com.android.systemui.keyboard.shortcut.qualifiers
import javax.inject.Qualifier
-@Qualifier
-@MustBeDocumented
-@Retention(AnnotationRetention.RUNTIME)
-annotation class IconLabelVisibilityLog()
+@Qualifier annotation class CurrentAppShortcuts
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutCategory.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutCategory.kt
index 63e167a376d1..4eabefcd2d41 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutCategory.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutCategory.kt
@@ -16,11 +16,16 @@
package com.android.systemui.keyboard.shortcut.shared.model
-enum class ShortcutCategoryType {
- SYSTEM,
- MULTI_TASKING,
- IME,
- APP_CATEGORIES,
+sealed interface ShortcutCategoryType {
+ data object System : ShortcutCategoryType
+
+ data object MultiTasking : ShortcutCategoryType
+
+ data object InputMethodEditor : ShortcutCategoryType
+
+ data object AppCategories : ShortcutCategoryType
+
+ data class CurrentApp(val packageName: String) : ShortcutCategoryType
}
data class ShortcutCategory(
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt
index 3b037bc17564..9e9368d3ffd3 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt
@@ -16,7 +16,10 @@
package com.android.systemui.keyboard.shortcut.ui.composable
+import android.content.Context
+import android.content.pm.PackageManager.NameNotFoundException
import android.graphics.drawable.Icon
+import android.util.Log
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.Image
@@ -55,6 +58,7 @@ import androidx.compose.material3.CenterAlignedTopAppBar
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
+import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.NavigationDrawerItemColors
import androidx.compose.material3.NavigationDrawerItemDefaults
@@ -76,7 +80,6 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.graphics.graphicsLayer
-import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.rememberNestedScrollInteropConnection
@@ -99,8 +102,10 @@ import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCommand
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutIcon
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutKey
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutSubCategory
+import com.android.systemui.keyboard.shortcut.ui.model.IconSource
import com.android.systemui.keyboard.shortcut.ui.model.ShortcutsUiState
import com.android.systemui.res.R
+import com.android.systemui.statusbar.phone.CentralSurfaces
@Composable
fun ShortcutHelper(
@@ -210,9 +215,9 @@ private fun CategoryItemSinglePane(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth().heightIn(min = 88.dp).padding(horizontal = 16.dp)
) {
- Icon(category.icon, contentDescription = null)
+ ShortcutCategoryIcon(category.icon)
Spacer(modifier = Modifier.width(16.dp))
- Text(stringResource(category.labelResId))
+ Text(category.label(LocalContext.current))
Spacer(modifier = Modifier.weight(1f))
RotatingExpandCollapseIcon(isExpanded)
}
@@ -221,23 +226,67 @@ private fun CategoryItemSinglePane(
}
}
-private val ShortcutCategory.icon: ImageVector
+private val ShortcutCategory.icon: IconSource
+ @Composable
get() =
when (type) {
- ShortcutCategoryType.SYSTEM -> Icons.Default.Tv
- ShortcutCategoryType.MULTI_TASKING -> Icons.Default.VerticalSplit
- ShortcutCategoryType.IME -> Icons.Default.Keyboard
- ShortcutCategoryType.APP_CATEGORIES -> Icons.Default.Apps
+ ShortcutCategoryType.System -> IconSource(imageVector = Icons.Default.Tv)
+ ShortcutCategoryType.MultiTasking ->
+ IconSource(imageVector = Icons.Default.VerticalSplit)
+ ShortcutCategoryType.InputMethodEditor ->
+ IconSource(imageVector = Icons.Default.Keyboard)
+ ShortcutCategoryType.AppCategories -> IconSource(imageVector = Icons.Default.Apps)
+ is ShortcutCategoryType.CurrentApp -> {
+ val context = LocalContext.current
+ val iconDrawable = context.packageManager.getApplicationIcon(type.packageName)
+ IconSource(painter = rememberDrawablePainter(drawable = iconDrawable))
+ }
}
-private val ShortcutCategory.labelResId: Int
- get() =
- when (type) {
- ShortcutCategoryType.SYSTEM -> R.string.shortcut_helper_category_system
- ShortcutCategoryType.MULTI_TASKING -> R.string.shortcut_helper_category_multitasking
- ShortcutCategoryType.IME -> R.string.shortcut_helper_category_input
- ShortcutCategoryType.APP_CATEGORIES -> R.string.shortcut_helper_category_app_shortcuts
- }
+@Composable
+fun ShortcutCategoryIcon(
+ source: IconSource,
+ contentDescription: String? = null,
+ modifier: Modifier = Modifier,
+ tint: Color = LocalContentColor.current
+) {
+ if (source.imageVector != null) {
+ Icon(source.imageVector, contentDescription, modifier, tint)
+ } else if (source.painter != null) {
+ Image(source.painter, contentDescription, modifier)
+ }
+}
+
+private fun ShortcutCategory.label(context: Context): String =
+ when (type) {
+ ShortcutCategoryType.System -> context.getString(R.string.shortcut_helper_category_system)
+ ShortcutCategoryType.MultiTasking ->
+ context.getString(R.string.shortcut_helper_category_multitasking)
+ ShortcutCategoryType.InputMethodEditor ->
+ context.getString(R.string.shortcut_helper_category_input)
+ ShortcutCategoryType.AppCategories ->
+ context.getString(R.string.shortcut_helper_category_app_shortcuts)
+ is ShortcutCategoryType.CurrentApp -> getApplicationLabelForCurrentApp(type, context)
+ }
+
+private fun getApplicationLabelForCurrentApp(
+ type: ShortcutCategoryType.CurrentApp,
+ context: Context
+): String {
+ val packageManagerForUser = CentralSurfaces.getPackageManagerForUser(context, context.userId)
+ return try {
+ val currentAppInfo =
+ packageManagerForUser.getApplicationInfoAsUser(
+ type.packageName,
+ /* flags = */ 0,
+ context.userId
+ )
+ packageManagerForUser.getApplicationLabel(currentAppInfo).toString()
+ } catch (e: NameNotFoundException) {
+ Log.wtf(ShortcutHelper.TAG, "Couldn't find app info by package name ${type.packageName}")
+ context.getString(R.string.shortcut_helper_category_current_app_shortcuts)
+ }
+}
@Composable
private fun RotatingExpandCollapseIcon(isExpanded: Boolean) {
@@ -525,8 +574,8 @@ private fun CategoriesPanelTwoPane(
Column {
categories.fastForEach {
CategoryItemTwoPane(
- label = stringResource(it.labelResId),
- icon = it.icon,
+ label = it.label(LocalContext.current),
+ iconSource = it.icon,
selected = selectedCategory == it.type,
onClick = { onCategoryClicked(it) }
)
@@ -537,7 +586,7 @@ private fun CategoriesPanelTwoPane(
@Composable
private fun CategoryItemTwoPane(
label: String,
- icon: ImageVector,
+ iconSource: IconSource,
selected: Boolean,
onClick: () -> Unit,
colors: NavigationDrawerItemColors =
@@ -551,9 +600,9 @@ private fun CategoryItemTwoPane(
color = colors.containerColor(selected).value,
) {
Row(Modifier.padding(horizontal = 24.dp), verticalAlignment = Alignment.CenterVertically) {
- Icon(
+ ShortcutCategoryIcon(
modifier = Modifier.size(24.dp),
- imageVector = icon,
+ source = iconSource,
contentDescription = null,
tint = colors.iconColor(selected).value
)
@@ -649,4 +698,6 @@ object ShortcutHelper {
object Dimensions {
val SinglePaneCategoryCornerRadius = 28.dp
}
+
+ internal const val TAG = "ShortcutHelperUI"
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/model/IconSource.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/model/IconSource.kt
new file mode 100644
index 000000000000..7fc0103d861f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/model/IconSource.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.keyboard.shortcut.ui.model
+
+import androidx.compose.ui.graphics.painter.Painter
+import androidx.compose.ui.graphics.vector.ImageVector
+
+data class IconSource(val imageVector: ImageVector? = null, val painter: Painter? = null)
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
index e602cad30daa..ad258f435d63 100644
--- 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
@@ -19,7 +19,6 @@ package com.android.systemui.keyboard.shortcut.ui.viewmodel
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.keyboard.shortcut.domain.interactor.ShortcutHelperCategoriesInteractor
import com.android.systemui.keyboard.shortcut.domain.interactor.ShortcutHelperStateInteractor
-import com.android.systemui.keyboard.shortcut.shared.model.ShortcutHelperState
import com.android.systemui.keyboard.shortcut.ui.model.ShortcutsUiState
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
@@ -40,8 +39,8 @@ constructor(
) {
val shouldShow =
- stateInteractor.state
- .map { it is ShortcutHelperState.Active }
+ categoriesInteractor.shortcutCategories
+ .map { it.isNotEmpty() }
.distinctUntilChanged()
.flowOn(backgroundDispatcher)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
index 33f9209fea09..80cf4c50866c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
@@ -21,6 +21,7 @@ import android.content.Context
import android.view.LayoutInflater
import android.view.View
import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.ComposeView
import androidx.constraintlayout.widget.ConstraintSet
@@ -29,9 +30,9 @@ import androidx.constraintlayout.widget.ConstraintSet.END
import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID
import androidx.constraintlayout.widget.ConstraintSet.START
import androidx.constraintlayout.widget.ConstraintSet.TOP
+import com.android.compose.animation.scene.MutableSceneTransitionLayoutState
import com.android.compose.animation.scene.SceneKey
import com.android.compose.animation.scene.SceneTransitionLayout
-import com.android.compose.animation.scene.transitions
import com.android.internal.jank.InteractionJankMonitor
import com.android.keyguard.KeyguardStatusView
import com.android.keyguard.KeyguardStatusViewController
@@ -115,7 +116,6 @@ constructor(
private var rootViewHandle: DisposableHandle? = null
private var indicationAreaHandle: DisposableHandle? = null
- private val sceneKey = SceneKey("root-view-scene-key")
var keyguardStatusViewController: KeyguardStatusViewController? = null
get() {
@@ -233,12 +233,10 @@ constructor(
setContent {
// STL is used solely to provide a SceneScope to enable us to invoke SceneScope
// composables.
- SceneTransitionLayout(
- currentScene = sceneKey,
- onChangeScene = {},
- transitions = transitions {},
- ) {
- scene(sceneKey) {
+ val currentScene = remember { SceneKey("root-view-scene-key") }
+ val state = remember { MutableSceneTransitionLayoutState(currentScene) }
+ SceneTransitionLayout(state) {
+ scene(currentScene) {
with(
LockscreenContent(
viewModel = viewModel,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index fe81b20c5367..2f872b6a6bc8 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -2834,6 +2834,14 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
*/
private void handleShow(Bundle options) {
Trace.beginSection("KeyguardViewMediator#handleShow");
+ try {
+ handleShowInner(options);
+ } finally {
+ Trace.endSection();
+ }
+ }
+
+ private void handleShowInner(Bundle options) {
final boolean showUnlocked = options != null
&& options.getBoolean(OPTION_SHOW_DISMISSIBLE, false);
final int currentUser = mSelectedUserInteractor.getSelectedUserId();
@@ -2885,8 +2893,6 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
mKeyguardDisplayManager.show();
scheduleNonStrongBiometricIdleTimeout();
-
- Trace.endSection();
}
/**
@@ -3065,6 +3071,17 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
RemoteAnimationTarget[] apps, RemoteAnimationTarget[] wallpapers,
RemoteAnimationTarget[] nonApps, IRemoteAnimationFinishedCallback finishedCallback) {
Trace.beginSection("KeyguardViewMediator#handleStartKeyguardExitAnimation");
+ try {
+ handleStartKeyguardExitAnimationInner(startTime, fadeoutDuration, apps, wallpapers,
+ nonApps, finishedCallback);
+ } finally {
+ Trace.endSection();
+ }
+ }
+
+ private void handleStartKeyguardExitAnimationInner(long startTime, long fadeoutDuration,
+ RemoteAnimationTarget[] apps, RemoteAnimationTarget[] wallpapers,
+ RemoteAnimationTarget[] nonApps, IRemoteAnimationFinishedCallback finishedCallback) {
Log.d(TAG, "handleStartKeyguardExitAnimation startTime=" + startTime
+ " fadeoutDuration=" + fadeoutDuration);
synchronized (KeyguardViewMediator.this) {
@@ -3253,8 +3270,6 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
onKeyguardExitFinished();
}
}
-
- Trace.endSection();
}
private void onKeyguardExitFinished() {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ResourceTrimmer.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ResourceTrimmer.kt
index 97ea16d7f8c8..b9e513586298 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ResourceTrimmer.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ResourceTrimmer.kt
@@ -24,11 +24,7 @@ import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
-import com.android.systemui.keyguard.shared.model.Edge
import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
-import com.android.systemui.keyguard.shared.model.TransitionState
-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.utils.GlobalWindowManager
import javax.inject.Inject
@@ -52,24 +48,15 @@ constructor(
private val globalWindowManager: GlobalWindowManager,
@Application private val applicationScope: CoroutineScope,
@Background private val bgDispatcher: CoroutineDispatcher,
- private val sceneInteractor: SceneInteractor,
) : CoreStartable {
override fun start() {
Log.d(LOG_TAG, "Resource trimmer registered.")
applicationScope.launch(bgDispatcher) {
- // We drop 1 to avoid triggering on initial collect().
- if (SceneContainerFlag.isEnabled) {
- sceneInteractor.transitionState
- .filter { it.isIdle(Scenes.Gone) }
- .collect { onKeyguardGone() }
- } else {
- keyguardTransitionInteractor.transition(Edge.create(to = GONE)).collect {
- if (it.transitionState == TransitionState.FINISHED) {
- onKeyguardGone()
- }
- }
- }
+ keyguardTransitionInteractor
+ .isFinishedIn(scene = Scenes.Gone, stateWithoutSceneContainer = GONE)
+ .filter { isOnGone -> isOnGone }
+ .collect { onKeyguardGone() }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt
index 1167cc47448c..893835a38c53 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt
@@ -137,6 +137,8 @@ constructor(
(KeyguardWmStateRefactor.isEnabled && canWakeDirectlyToGone)
if (shouldTransitionToGone) {
+ // TODO(b/336576536): Check if adaptation for scene framework is needed
+ if (SceneContainerFlag.isEnabled) return@collect
startTransitionTo(
toState = KeyguardState.GONE,
)
@@ -197,6 +199,7 @@ constructor(
* PRIMARY_BOUNCER.
*/
private fun listenForAodToPrimaryBouncer() {
+ // TODO(b/336576536): Check if adaptation for scene framework is needed
if (SceneContainerFlag.isEnabled) return
scope.launch("$TAG#listenForAodToPrimaryBouncer") {
keyguardInteractor.primaryBouncerShowing
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 aee65a81880d..cd28bec938b8 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
@@ -17,8 +17,11 @@
package com.android.systemui.keyguard.domain.interactor
import android.animation.ValueAnimator
+import android.annotation.SuppressLint
+import android.app.DreamManager
import com.android.app.animation.Interpolators
import com.android.systemui.communal.domain.interactor.CommunalInteractor
+import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
@@ -28,6 +31,7 @@ import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepositor
import com.android.systemui.keyguard.shared.model.BiometricUnlockMode.Companion.isWakeAndUnlock
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.power.domain.interactor.PowerInteractor
+import com.android.systemui.power.shared.model.WakeSleepReason
import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.util.kotlin.Utils.Companion.sample
import com.android.systemui.util.kotlin.sample
@@ -53,9 +57,11 @@ constructor(
keyguardInteractor: KeyguardInteractor,
powerInteractor: PowerInteractor,
private val communalInteractor: CommunalInteractor,
+ private val communalSceneInteractor: CommunalSceneInteractor,
keyguardOcclusionInteractor: KeyguardOcclusionInteractor,
val deviceEntryRepository: DeviceEntryRepository,
private val wakeToGoneInteractor: KeyguardWakeDirectlyToGoneInteractor,
+ private val dreamManager: DreamManager,
) :
TransitionInteractor(
fromState = KeyguardState.DOZING,
@@ -115,6 +121,7 @@ constructor(
}
}
+ @SuppressLint("MissingPermission")
private fun listenForDozingToAny() {
if (KeyguardWmStateRefactor.isEnabled) {
return
@@ -126,7 +133,8 @@ constructor(
.filterRelevantKeyguardStateAnd { isAwake -> isAwake }
.sample(
keyguardInteractor.isKeyguardOccluded,
- communalInteractor.isIdleOnCommunal,
+ communalInteractor.isCommunalAvailable,
+ communalSceneInteractor.isIdleOnCommunal,
canTransitionToGoneOnWake,
keyguardInteractor.primaryBouncerShowing,
)
@@ -134,6 +142,7 @@ constructor(
(
_,
occluded,
+ isCommunalAvailable,
isIdleOnCommunal,
canTransitionToGoneOnWake,
primaryBouncerShowing) ->
@@ -163,6 +172,19 @@ constructor(
} else {
startTransitionTo(KeyguardState.GLANCEABLE_HUB)
}
+ } else if (
+ powerInteractor.detailedWakefulness.value.lastWakeReason ==
+ WakeSleepReason.POWER_BUTTON &&
+ isCommunalAvailable &&
+ dreamManager.canStartDreaming(true)
+ ) {
+ // This case handles tapping the power button to transition through
+ // dream -> off -> hub.
+ if (SceneContainerFlag.isEnabled) {
+ // TODO(b/336576536): Check if adaptation for scene framework is needed
+ } else {
+ startTransitionTo(KeyguardState.GLANCEABLE_HUB)
+ }
} else {
startTransitionTo(KeyguardState.LOCKSCREEN)
}
@@ -171,6 +193,7 @@ constructor(
}
/** Figure out what state to transition to when we awake from DOZING. */
+ @SuppressLint("MissingPermission")
private fun listenForWakeFromDozing() {
if (!KeyguardWmStateRefactor.isEnabled) {
return
@@ -180,7 +203,8 @@ constructor(
powerInteractor.detailedWakefulness
.filterRelevantKeyguardStateAnd { it.isAwake() }
.sample(
- communalInteractor.isIdleOnCommunal,
+ communalInteractor.isCommunalAvailable,
+ communalSceneInteractor.isIdleOnCommunal,
keyguardInteractor.biometricUnlockState,
wakeToGoneInteractor.canWakeDirectlyToGone,
keyguardInteractor.primaryBouncerShowing,
@@ -188,6 +212,7 @@ constructor(
.collect {
(
_,
+ isCommunalAvailable,
isIdleOnCommunal,
biometricUnlockState,
canWakeDirectlyToGone,
@@ -227,6 +252,23 @@ constructor(
ownerReason = "waking from dozing"
)
}
+ } else if (
+ powerInteractor.detailedWakefulness.value.lastWakeReason ==
+ WakeSleepReason.POWER_BUTTON &&
+ isCommunalAvailable &&
+ dreamManager.canStartDreaming(true)
+ ) {
+ // This case handles tapping the power button to transition through
+ // dream -> off -> hub.
+ if (SceneContainerFlag.isEnabled) {
+ // TODO(b/336576536): Check if adaptation for scene framework is
+ // needed
+ } else {
+ startTransitionTo(
+ KeyguardState.GLANCEABLE_HUB,
+ ownerReason = "waking from dozing"
+ )
+ }
} else {
startTransitionTo(
KeyguardState.LOCKSCREEN,
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 8041dd933143..2eca9e12d7ee 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
@@ -167,6 +167,8 @@ constructor(
}
private fun listenForHubToGone() {
+ // TODO(b/336576536): Check if adaptation for scene framework is needed
+ if (SceneContainerFlag.isEnabled) return
scope.launch {
keyguardInteractor.isKeyguardGoingAway
.filterRelevantKeyguardStateAnd { isKeyguardGoingAway -> isKeyguardGoingAway }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
index ff15a1bc34d0..343a1351adef 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
@@ -272,10 +272,9 @@ constructor(
}
private fun listenForLockscreenToGone() {
- if (KeyguardWmStateRefactor.isEnabled) {
- return
- }
-
+ // TODO(b/336576536): Check if adaptation for scene framework is needed
+ if (SceneContainerFlag.isEnabled) return
+ if (KeyguardWmStateRefactor.isEnabled) return
scope.launch("$TAG#listenForLockscreenToGone") {
keyguardInteractor.isKeyguardGoingAway
.filterRelevantKeyguardStateAnd { isKeyguardGoingAway -> isKeyguardGoingAway }
@@ -289,6 +288,7 @@ constructor(
}
private fun listenForLockscreenToGoneDragging() {
+ // TODO(b/336576536): Check if adaptation for scene framework is needed
if (SceneContainerFlag.isEnabled) return
if (KeyguardWmStateRefactor.isEnabled) {
// When the refactor is enabled, we no longer use isKeyguardGoingAway.
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt
index 84ca6672d509..f3ca9df6491c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt
@@ -71,6 +71,8 @@ constructor(
}
private fun listenForOccludedToPrimaryBouncer() {
+ // TODO(b/336576536): Check if adaptation for scene framework is needed
+ if (SceneContainerFlag.isEnabled) return
scope.launch {
keyguardInteractor.primaryBouncerShowing
.filterRelevantKeyguardStateAnd { isBouncerShowing -> isBouncerShowing }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
index f98ed15a21c6..24290881a0fb 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
@@ -40,7 +40,6 @@ import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.distinctUntilChanged
-import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.launch
@@ -81,25 +80,18 @@ constructor(
}
val surfaceBehindVisibility: Flow<Boolean?> =
- if (SceneContainerFlag.isEnabled) {
- // The edge Scenes.Bouncer <-> Scenes.Gone is handled by STL
- flowOf(null)
- } else {
- transitionInteractor
- .transition(
- edge = Edge.INVALID,
- edgeWithoutSceneContainer =
- Edge.create(from = KeyguardState.PRIMARY_BOUNCER, to = KeyguardState.GONE)
- )
- .map<TransitionStep, Boolean?> {
- it.value > TO_GONE_SURFACE_BEHIND_VISIBLE_THRESHOLD
- }
- .onStart {
- // Default to null ("don't care, use a reasonable default").
- emit(null)
- }
- .distinctUntilChanged()
- }
+ transitionInteractor
+ .transition(
+ edge = Edge.INVALID,
+ edgeWithoutSceneContainer =
+ Edge.create(from = KeyguardState.PRIMARY_BOUNCER, to = KeyguardState.GONE)
+ )
+ .map<TransitionStep, Boolean?> { it.value > TO_GONE_SURFACE_BEHIND_VISIBLE_THRESHOLD }
+ .onStart {
+ // Default to null ("don't care, use a reasonable default").
+ emit(null)
+ }
+ .distinctUntilChanged()
fun dismissPrimaryBouncer() {
scope.launch { startTransitionTo(KeyguardState.GONE) }
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 41c39597dc02..e2bb540f6645 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
@@ -19,7 +19,6 @@
package com.android.systemui.keyguard.domain.interactor
-import android.content.Context
import com.android.systemui.CoreStartable
import com.android.systemui.biometrics.domain.interactor.FingerprintPropertyInteractor
import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor
@@ -32,15 +31,12 @@ import com.android.systemui.keyguard.ui.view.layout.blueprints.DefaultKeyguardBl
import com.android.systemui.keyguard.ui.view.layout.blueprints.SplitShadeKeyguardBlueprint
import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.IntraBlueprintTransition.Config
import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.IntraBlueprintTransition.Type
-import com.android.systemui.keyguard.ui.view.layout.sections.ClockSection
import com.android.systemui.keyguard.ui.view.layout.sections.SmartspaceSection
import com.android.systemui.shade.domain.interactor.ShadeInteractor
-import com.android.systemui.shade.shared.model.ShadeMode
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
@@ -51,13 +47,10 @@ class KeyguardBlueprintInteractor
constructor(
private val keyguardBlueprintRepository: KeyguardBlueprintRepository,
@Application private val applicationScope: CoroutineScope,
- private val context: Context,
- private val shadeInteractor: ShadeInteractor,
- private val clockInteractor: KeyguardClockInteractor,
+ shadeInteractor: ShadeInteractor,
private val configurationInteractor: ConfigurationInteractor,
private val fingerprintPropertyInteractor: FingerprintPropertyInteractor,
private val smartspaceSection: SmartspaceSection,
- private val clockSection: ClockSection,
) : CoreStartable {
/** The current blueprint for the lockscreen. */
val blueprint: StateFlow<KeyguardBlueprint> = keyguardBlueprintRepository.blueprint
@@ -70,8 +63,8 @@ constructor(
/** Current BlueprintId */
val blueprintId =
- shadeInteractor.shadeMode.map { shadeMode ->
- val useSplitShade = shadeMode == ShadeMode.Split && !ComposeLockscreen.isEnabled
+ shadeInteractor.isShadeLayoutWide.map { isShadeLayoutWide ->
+ val useSplitShade = isShadeLayoutWide && !ComposeLockscreen.isEnabled
when {
useSplitShade -> SplitShadeKeyguardBlueprint.ID
else -> DefaultKeyguardBlueprint.DEFAULT
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt
index 142b1a031277..c0049d4e2e6c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt
@@ -31,7 +31,6 @@ import com.android.systemui.plugins.clocks.ClockController
import com.android.systemui.plugins.clocks.ClockId
import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.shade.domain.interactor.ShadeInteractor
-import com.android.systemui.shade.shared.model.ShadeMode
import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor
import com.android.systemui.statusbar.notification.domain.interactor.HeadsUpNotificationInteractor
import com.android.systemui.util.kotlin.combine
@@ -45,6 +44,7 @@ import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
private val TAG = KeyguardClockInteractor::class.simpleName
+
/** Manages and encapsulates the clock components of the lockscreen root view. */
@SysUISingleton
class KeyguardClockInteractor
@@ -77,16 +77,16 @@ constructor(
val clockSize: StateFlow<ClockSize> =
if (SceneContainerFlag.isEnabled) {
combine(
- shadeInteractor.shadeMode,
+ shadeInteractor.isShadeLayoutWide,
activeNotificationsInteractor.areAnyNotificationsPresent,
mediaCarouselInteractor.hasActiveMediaOrRecommendation,
keyguardInteractor.isDozing,
isOnAod,
- ) { shadeMode, hasNotifs, hasMedia, isDozing, isOnAod ->
+ ) { isShadeLayoutWide, hasNotifs, hasMedia, isDozing, isOnAod ->
return@combine when {
keyguardClockRepository.shouldForceSmallClock && !isOnAod -> ClockSize.SMALL
- shadeMode == ShadeMode.Single && (hasNotifs || hasMedia) -> ClockSize.SMALL
- shadeMode == ShadeMode.Single -> ClockSize.LARGE
+ !isShadeLayoutWide && (hasNotifs || hasMedia) -> ClockSize.SMALL
+ !isShadeLayoutWide -> ClockSize.LARGE
hasMedia && !isDozing -> ClockSize.SMALL
else -> ClockSize.LARGE
}
@@ -103,21 +103,21 @@ constructor(
val clockShouldBeCentered: Flow<Boolean> =
if (SceneContainerFlag.isEnabled) {
combine(
- shadeInteractor.shadeMode,
+ shadeInteractor.isShadeLayoutWide,
activeNotificationsInteractor.areAnyNotificationsPresent,
keyguardInteractor.isActiveDreamLockscreenHosted,
isOnAod,
headsUpNotificationInteractor.isHeadsUpOrAnimatingAway,
keyguardInteractor.isDozing,
) {
- shadeMode,
+ isShadeLayoutWide,
areAnyNotificationsPresent,
isActiveDreamLockscreenHosted,
isOnAod,
isHeadsUp,
isDozing ->
when {
- shadeMode != ShadeMode.Split -> true
+ !isShadeLayoutWide -> true
!areAnyNotificationsPresent -> true
isActiveDreamLockscreenHosted -> true
// Pulsing notification appears on the right. Move clock left to avoid overlap.
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractor.kt
index 1aac1c5940b3..f4d82659971d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractor.kt
@@ -25,9 +25,8 @@ import com.android.systemui.keyguard.shared.model.KeyguardDone
import com.android.systemui.keyguard.shared.model.KeyguardState.ALTERNATE_BOUNCER
import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
import com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER
-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.util.kotlin.Utils.Companion.sampleFilter
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
@@ -35,6 +34,7 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.filterNot
import kotlinx.coroutines.flow.map
@@ -51,7 +51,6 @@ constructor(
transitionInteractor: KeyguardTransitionInteractor,
val dismissInteractor: KeyguardDismissInteractor,
@Application private val applicationScope: CoroutineScope,
- sceneInteractor: SceneInteractor,
) {
val dismissAction: Flow<DismissAction> = repository.dismissAction
@@ -76,11 +75,10 @@ constructor(
)
private val finishedTransitionToGone: Flow<Unit> =
- if (SceneContainerFlag.isEnabled) {
- sceneInteractor.transitionState.filter { it.isIdle(Scenes.Gone) }.map {}
- } else {
- transitionInteractor.finishedKeyguardState.filter { it == GONE }.map {}
- }
+ transitionInteractor
+ .isFinishedIn(scene = Scenes.Gone, stateWithoutSceneContainer = GONE)
+ .filter { it }
+ .map {}
val executeDismissAction: Flow<() -> KeyguardDone> =
merge(
@@ -90,12 +88,24 @@ constructor(
.sample(dismissAction)
.filterNot { it is DismissAction.None }
.map { it.onDismissAction }
+
val resetDismissAction: Flow<Unit> =
- transitionInteractor.finishedKeyguardTransitionStep
- .filter { it.to != ALTERNATE_BOUNCER && it.to != PRIMARY_BOUNCER && it.to != GONE }
- .sample(dismissAction)
- .filterNot { it is DismissAction.None }
- .map {} // map to Unit
+ combine(
+ transitionInteractor.isFinishedIn(
+ scene = Scenes.Gone,
+ stateWithoutSceneContainer = GONE
+ ),
+ transitionInteractor.isFinishedIn(
+ scene = Scenes.Bouncer,
+ stateWithoutSceneContainer = PRIMARY_BOUNCER
+ ),
+ transitionInteractor.isFinishedIn(state = ALTERNATE_BOUNCER)
+ ) { isOnGone, isOnBouncer, isOnAltBouncer ->
+ !isOnGone && !isOnBouncer && !isOnAltBouncer
+ }
+ .filter { it }
+ .sampleFilter(dismissAction) { it !is DismissAction.None }
+ .map {}
fun runDismissAnimationOnKeyguard(): Boolean {
return willAnimateDismissActionOnLockscreen.value
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardEnabledInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardEnabledInteractor.kt
index 66efde1c8358..4aef8084e5e7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardEnabledInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardEnabledInteractor.kt
@@ -90,17 +90,13 @@ constructor(
* GONE.
*/
scope.launch {
- repository.isKeyguardEnabled
- .filter { enabled -> !enabled }
- .sampleCombine(
- biometricSettingsRepository.isCurrentUserInLockdown,
- internalTransitionInteractor.currentTransitionInfoInternal,
- )
- .collect { (_, inLockdown, currentTransitionInfo) ->
- if (currentTransitionInfo.to != KeyguardState.GONE && !inLockdown) {
+ if (!SceneContainerFlag.isEnabled) {
+ showKeyguardWhenReenabled
+ .filter { shouldDismiss -> shouldDismiss }
+ .collect {
transitionInteractor.startDismissKeyguardTransition("keyguard disabled")
}
- }
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
index 859326a29b28..ec03a6d8121f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
@@ -52,7 +52,6 @@ import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.notification.NotificationUtils.interpolate
import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor
import com.android.systemui.util.kotlin.Utils.Companion.sample as sampleCombine
-import com.android.systemui.util.kotlin.Utils.Companion.sampleFilter
import com.android.systemui.util.kotlin.pairwise
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
@@ -251,13 +250,17 @@ constructor(
/** Keyguard can be clipped at the top as the shade is dragged */
val topClippingBounds: Flow<Int?> by lazy {
- repository.topClippingBounds
- .sampleFilter(
+ combineTransform(
keyguardTransitionInteractor
.transitionValue(scene = Scenes.Gone, stateWithoutSceneContainer = GONE)
- .onStart { emit(0f) }
- ) { goneValue ->
- goneValue != 1f
+ .map { it == 1f }
+ .onStart { emit(false) }
+ .distinctUntilChanged(),
+ repository.topClippingBounds
+ ) { isGone, topClippingBounds ->
+ if (!isGone) {
+ emit(topClippingBounds)
+ }
}
.distinctUntilChanged()
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardOcclusionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardOcclusionInteractor.kt
index 5af38ba49b85..7f1e881c0863 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardOcclusionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardOcclusionInteractor.kt
@@ -97,8 +97,8 @@ constructor(
powerInteractor.detailedWakefulness
.sample(
transitionInteractor.isFinishedIn(
- Scenes.Gone,
- stateWithoutSceneContainer = KeyguardState.GONE
+ scene = Scenes.Gone,
+ stateWithoutSceneContainer = KeyguardState.GONE,
),
::Pair
)
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 bcbdc9cca83b..377a03edf88d 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
@@ -58,12 +58,12 @@ constructor(
val viewParams: Flow<KeyguardSurfaceBehindModel> =
combine(
transitionInteractor.isInTransition(
- Edge.create(to = Scenes.Gone),
- edgeWithoutSceneContainer = Edge.create(to = KeyguardState.GONE)
+ edge = Edge.create(to = Scenes.Gone),
+ edgeWithoutSceneContainer = Edge.create(to = KeyguardState.GONE),
),
transitionInteractor.isFinishedIn(
- Scenes.Gone,
- stateWithoutSceneContainer = KeyguardState.GONE
+ scene = Scenes.Gone,
+ stateWithoutSceneContainer = KeyguardState.GONE,
),
notificationLaunchInteractor.isLaunchAnimationRunning,
) { transitioningToGone, isOnGone, notifAnimationRunning ->
@@ -112,8 +112,8 @@ constructor(
notificationLaunchInteractor.isLaunchAnimationRunning
.sample(
transitionInteractor.isFinishedIn(
- Scenes.Gone,
- stateWithoutSceneContainer = KeyguardState.GONE
+ scene = Scenes.Gone,
+ stateWithoutSceneContainer = KeyguardState.GONE,
),
::Pair
)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardWakeDirectlyToGoneInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardWakeDirectlyToGoneInteractor.kt
index 6a1b7cfb7d7e..f0bf4029ab39 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardWakeDirectlyToGoneInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardWakeDirectlyToGoneInteractor.kt
@@ -29,6 +29,7 @@ import com.android.internal.widget.LockPatternUtils
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.KeyguardViewMediator
+import com.android.systemui.keyguard.KeyguardWmStateRefactor
import com.android.systemui.keyguard.data.repository.KeyguardRepository
import com.android.systemui.keyguard.shared.model.BiometricUnlockMode
import com.android.systemui.keyguard.shared.model.KeyguardState
@@ -257,6 +258,10 @@ constructor(
/** Set an alarm for */
private fun setResetCanIgnoreAuthAlarm() {
+ if (!KeyguardWmStateRefactor.isEnabled) {
+ return
+ }
+
val intent =
Intent(DELAYED_KEYGUARD_ACTION).apply {
setPackage(context.packageName)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt
index 0985e69ff8ff..e1b333dd1d06 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt
@@ -82,6 +82,7 @@ constructor(
private val transitionSpecificSurfaceBehindVisibility: Flow<Boolean?> =
transitionInteractor.startedKeyguardTransitionStep
.flatMapLatest { startedStep ->
+ SceneContainerFlag.assertInLegacyMode()
when (startedStep.from) {
KeyguardState.LOCKSCREEN -> {
fromLockscreenInteractor.surfaceBehindVisibility
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardState.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardState.kt
index 8db6a43efc07..24db3c2c70a2 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardState.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardState.kt
@@ -61,6 +61,11 @@ enum class KeyguardState {
* The security screen prompt UI, containing PIN, Password, Pattern for the user to verify their
* credentials.
*/
+ @Deprecated(
+ "This state won't exist anymore when scene container gets enabled. If you are " +
+ "writing prod code today, make sure to either use flag aware APIs in " +
+ "[KeyguardTransitionInteractor] or flag appropriately with [SceneContainerFlag]."
+ )
PRIMARY_BOUNCER,
/**
* Device is actively displaying keyguard UI and is not in low-power mode. Device may be
@@ -72,12 +77,22 @@ enum class KeyguardState {
* hub UI. From this state, the user can swipe from the left edge to go back to the lock screen
* or dream, as well as swipe down for the notifications and up for the bouncer.
*/
+ @Deprecated(
+ "This state won't exist anymore when scene container gets enabled. If you are " +
+ "writing prod code today, make sure to either use flag aware APIs in " +
+ "[KeyguardTransitionInteractor] or flag appropriately with [SceneContainerFlag]."
+ )
GLANCEABLE_HUB,
/**
* Keyguard is no longer visible. In most cases the user has just authenticated and keyguard is
* being removed, but there are other cases where the user is swiping away keyguard, such as
* with SWIPE security method or face unlock without bypass.
*/
+ @Deprecated(
+ "This state won't exist anymore when scene container gets enabled. If you are " +
+ "writing prod code today, make sure to either use flag aware APIs in " +
+ "[KeyguardTransitionInteractor] or flag appropriately with [SceneContainerFlag]."
+ )
GONE,
/**
* Only used in scene framework. This means we are currently on any scene framework scene that
@@ -143,6 +158,7 @@ enum class KeyguardState {
/** Whether the lockscreen is visible when we're FINISHED in the given state. */
fun lockscreenVisibleInState(state: KeyguardState): Boolean {
+ // TODO(b/349784682): Transform deprecated states for Flexiglass
return state != GONE
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlows.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlows.kt
index caa043622e18..8485a265fc70 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlows.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlows.kt
@@ -22,6 +22,7 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardDismissActionInte
import com.android.systemui.keyguard.shared.model.Edge
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
+import com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER
import com.android.systemui.keyguard.shared.model.ScrimAlpha
import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
import com.android.systemui.scene.shared.flag.SceneContainerFlag
@@ -75,9 +76,12 @@ constructor(
return animationFlow
.setup(
duration = duration,
- // TODO(b/330311871): from can be PRIMARY_BOUNCER which would be a scene -> scene
- // transition
- edge = Edge.create(from = from, to = Scenes.Gone)
+ edge =
+ if (from == PRIMARY_BOUNCER) {
+ Edge.INVALID
+ } else {
+ Edge.create(from = from, to = Scenes.Gone)
+ }
)
.setupWithoutSceneContainer(
edge = Edge.create(from = from, to = GONE),
@@ -105,9 +109,12 @@ constructor(
animationFlow
.setup(
duration = duration,
- // TODO(b/330311871): from can be PRIMARY_BOUNCER which would be a scene ->
- // scene transition
- edge = Edge.create(from = fromState, to = Scenes.Gone),
+ edge =
+ if (fromState == PRIMARY_BOUNCER) {
+ Edge.INVALID
+ } else {
+ Edge.create(from = fromState, to = Scenes.Gone)
+ }
)
.setupWithoutSceneContainer(
edge = Edge.create(from = fromState, to = GONE),
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToGlanceableHubTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToGlanceableHubTransitionViewModel.kt
index 8eab406a1273..6a3573ab0119 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToGlanceableHubTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToGlanceableHubTransitionViewModel.kt
@@ -23,7 +23,6 @@ import com.android.systemui.keyguard.shared.model.KeyguardState.GLANCEABLE_HUB
import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition
-import com.android.systemui.scene.shared.model.Scenes
import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.flow.Flow
@@ -37,7 +36,7 @@ constructor(
private val transitionAnimation =
animationFlow
- .setup(duration = TO_GLANCEABLE_HUB_DURATION, edge = Edge.create(GONE, Scenes.Communal))
+ .setup(duration = TO_GLANCEABLE_HUB_DURATION, edge = Edge.INVALID)
.setupWithoutSceneContainer(edge = Edge.create(GONE, GLANCEABLE_HUB))
override val deviceEntryParentViewAlpha: Flow<Float> =
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt
index 573b75e623fb..73028c5cf496 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt
@@ -30,7 +30,6 @@ import com.android.systemui.keyguard.shared.model.ClockSize
import com.android.systemui.keyguard.shared.model.ClockSizeSetting
import com.android.systemui.res.R
import com.android.systemui.shade.domain.interactor.ShadeInteractor
-import com.android.systemui.shade.shared.model.ShadeMode
import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerAlwaysOnDisplayViewModel
import com.android.systemui.statusbar.ui.SystemBarUtilsProxy
import javax.inject.Inject
@@ -119,26 +118,25 @@ constructor(
combine(
isLargeClockVisible,
clockShouldBeCentered,
- shadeInteractor.shadeMode,
+ shadeInteractor.isShadeLayoutWide,
currentClock,
- ) { isLargeClockVisible, clockShouldBeCentered, shadeMode, currentClock ->
- val shouldUseSplitShade = shadeMode == ShadeMode.Split
+ ) { isLargeClockVisible, clockShouldBeCentered, isShadeLayoutWide, currentClock ->
if (currentClock?.config?.useCustomClockScene == true) {
when {
- shouldUseSplitShade && clockShouldBeCentered ->
+ isShadeLayoutWide && clockShouldBeCentered ->
ClockLayout.WEATHER_LARGE_CLOCK
- shouldUseSplitShade && isLargeClockVisible ->
+ isShadeLayoutWide && isLargeClockVisible ->
ClockLayout.SPLIT_SHADE_WEATHER_LARGE_CLOCK
- shouldUseSplitShade -> ClockLayout.SPLIT_SHADE_SMALL_CLOCK
+ isShadeLayoutWide -> ClockLayout.SPLIT_SHADE_SMALL_CLOCK
isLargeClockVisible -> ClockLayout.WEATHER_LARGE_CLOCK
else -> ClockLayout.SMALL_CLOCK
}
} else {
when {
- shouldUseSplitShade && clockShouldBeCentered -> ClockLayout.LARGE_CLOCK
- shouldUseSplitShade && isLargeClockVisible ->
+ isShadeLayoutWide && clockShouldBeCentered -> ClockLayout.LARGE_CLOCK
+ isShadeLayoutWide && isLargeClockVisible ->
ClockLayout.SPLIT_SHADE_LARGE_CLOCK
- shouldUseSplitShade -> ClockLayout.SPLIT_SHADE_SMALL_CLOCK
+ isShadeLayoutWide -> ClockLayout.SPLIT_SHADE_SMALL_CLOCK
isLargeClockVisible -> ClockLayout.LARGE_CLOCK
else -> ClockLayout.SMALL_CLOCK
}
@@ -164,7 +162,7 @@ constructor(
/** Calculates the top margin for the small clock. */
fun getSmallClockTopMargin(): Int {
val statusBarHeight = systemBarUtils.getStatusBarHeaderHeightKeyguard()
- return if (shadeInteractor.shadeMode.value == ShadeMode.Split) {
+ return if (shadeInteractor.isShadeLayoutWide.value) {
resources.getDimensionPixelSize(R.dimen.keyguard_split_shade_top_margin) -
if (ComposeLockscreen.isEnabled) statusBarHeight else 0
} else {
@@ -176,7 +174,7 @@ constructor(
val smallClockTopMargin =
combine(
configurationInteractor.onAnyConfigurationChange,
- shadeInteractor.shadeMode,
+ shadeInteractor.isShadeLayoutWide,
) { _, _ ->
getSmallClockTopMargin()
}
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 0fb29c297002..7c468071d1f8 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
@@ -160,7 +160,7 @@ constructor(
edgeWithoutSceneContainer = Edge.create(from = LOCKSCREEN, to = GONE),
),
keyguardTransitionInteractor.isInTransition(
- edge = Edge.create(from = PRIMARY_BOUNCER, to = Scenes.Lockscreen),
+ edge = Edge.create(from = Scenes.Bouncer, to = LOCKSCREEN),
edgeWithoutSceneContainer =
Edge.create(from = PRIMARY_BOUNCER, to = LOCKSCREEN),
),
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModel.kt
index 8a29f96d3fcd..3b337fc3f7c8 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModel.kt
@@ -27,7 +27,6 @@ import com.android.systemui.keyguard.shared.model.ClockSize
import com.android.systemui.res.R
import com.android.systemui.scene.domain.interactor.SceneContainerOcclusionInteractor
import com.android.systemui.shade.domain.interactor.ShadeInteractor
-import com.android.systemui.shade.shared.model.ShadeMode
import com.android.systemui.unfold.domain.interactor.UnfoldTransitionInteractor
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
@@ -56,21 +55,14 @@ constructor(
val isUdfpsVisible: Boolean
get() = authController.isUdfpsSupported
- val shouldUseSplitNotificationShade: StateFlow<Boolean> =
- shadeInteractor.shadeMode
- .map { it == ShadeMode.Split }
- .stateIn(
- scope = applicationScope,
- started = SharingStarted.WhileSubscribed(),
- initialValue = false,
- )
+ val isShadeLayoutWide: StateFlow<Boolean> = shadeInteractor.isShadeLayoutWide
val areNotificationsVisible: StateFlow<Boolean> =
combine(
clockSize,
- shouldUseSplitNotificationShade,
- ) { clockSize, shouldUseSplitNotificationShade ->
- clockSize == ClockSize.SMALL || shouldUseSplitNotificationShade
+ shadeInteractor.isShadeLayoutWide,
+ ) { clockSize, isShadeLayoutWide ->
+ clockSize == ClockSize.SMALL || isShadeLayoutWide
}
.stateIn(
scope = applicationScope,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGlanceableHubTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGlanceableHubTransitionViewModel.kt
index 754fb94a572e..9ec15dcff5f4 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGlanceableHubTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGlanceableHubTransitionViewModel.kt
@@ -23,7 +23,6 @@ import com.android.systemui.keyguard.shared.model.KeyguardState.GLANCEABLE_HUB
import com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER
import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition
-import com.android.systemui.scene.shared.model.Scenes
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
@@ -33,10 +32,7 @@ class PrimaryBouncerToGlanceableHubTransitionViewModel
constructor(animationFlow: KeyguardTransitionAnimationFlow) : DeviceEntryIconTransition {
private val transitionAnimation =
animationFlow
- .setup(
- duration = TO_GLANCEABLE_HUB_DURATION,
- edge = Edge.create(PRIMARY_BOUNCER, Scenes.Communal)
- )
+ .setup(duration = TO_GLANCEABLE_HUB_DURATION, edge = Edge.INVALID)
.setupWithoutSceneContainer(edge = Edge.create(PRIMARY_BOUNCER, GLANCEABLE_HUB))
override val deviceEntryParentViewAlpha: Flow<Float> =
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt
index 7ae455818952..46ba5d13bb6d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt
@@ -26,7 +26,6 @@ import com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER
import com.android.systemui.keyguard.shared.model.ScrimAlpha
import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
import com.android.systemui.scene.shared.flag.SceneContainerFlag
-import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.statusbar.SysuiStatusBarStateController
import dagger.Lazy
import javax.inject.Inject
@@ -54,7 +53,7 @@ constructor(
animationFlow
.setup(
duration = TO_GONE_DURATION,
- edge = Edge.create(from = PRIMARY_BOUNCER, to = Scenes.Gone),
+ edge = Edge.INVALID,
)
.setupWithoutSceneContainer(
edge = Edge.create(from = PRIMARY_BOUNCER, to = GONE),
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
index 52b0b87ddb58..d1c9b8ea1803 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
@@ -369,9 +369,9 @@ public class LogModule {
*/
@Provides
@SysUISingleton
- @MediaLoadingLog
- public static LogBuffer providesMediaLoadingLogBuffer(LogBufferFactory factory) {
- return factory.create("MediaLoadingLog", 20);
+ @MediaLog
+ public static LogBuffer providesMediaLogBuffer(LogBufferFactory factory) {
+ return factory.create("MediaLog", 20);
}
/** Allows logging buffers to be tweaked via adb on debug builds but not on prod builds. */
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/MediaLoadingLog.kt b/packages/SystemUI/src/com/android/systemui/log/dagger/MediaLog.kt
index 05e1b2e2cd23..d1dc6f394ee5 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/MediaLoadingLog.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/MediaLog.kt
@@ -19,8 +19,5 @@ package com.android.systemui.log.dagger
import com.android.systemui.log.LogBuffer
import javax.inject.Qualifier
-/** A [LogBuffer] for [com.android.systemui.media.controls.domain.pipeline.MediaLoadingLogger] */
-@Qualifier
-@MustBeDocumented
-@Retention(AnnotationRetention.RUNTIME)
-annotation class MediaLoadingLog
+/** A [LogBuffer] for [com.android.systemui.media.controls.shared.MediaLogger] */
+@Qualifier @MustBeDocumented @Retention(AnnotationRetention.RUNTIME) annotation class MediaLog
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilterImpl.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilterImpl.kt
index 803e7efa7f60..68f1af311b1b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilterImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilterImpl.kt
@@ -27,6 +27,7 @@ import com.android.systemui.broadcast.BroadcastSender
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.media.controls.data.repository.MediaFilterRepository
+import com.android.systemui.media.controls.shared.MediaLogger
import com.android.systemui.media.controls.shared.model.EXTRA_KEY_TRIGGER_RESUME
import com.android.systemui.media.controls.shared.model.MediaData
import com.android.systemui.media.controls.shared.model.MediaDataLoadingModel
@@ -70,7 +71,7 @@ constructor(
private val logger: MediaUiEventLogger,
private val mediaFlags: MediaFlags,
private val mediaFilterRepository: MediaFilterRepository,
- private val mediaLoadingLogger: MediaLoadingLogger,
+ private val mediaLogger: MediaLogger,
) : MediaDataManager.Listener {
/** Non-UI listeners to media changes. */
private val _listeners: MutableSet<MediaDataProcessor.Listener> = mutableSetOf()
@@ -118,7 +119,7 @@ constructor(
val isUpdate = mediaFilterRepository.addSelectedUserMediaEntry(data)
- mediaLoadingLogger.logMediaLoaded(data.instanceId, data.active, "loading media")
+ mediaLogger.logMediaLoaded(data.instanceId, data.active, "loading media")
mediaFilterRepository.addMediaDataLoadingState(
MediaDataLoadingModel.Loaded(data.instanceId),
isUpdate
@@ -189,7 +190,7 @@ constructor(
isSsReactivated = true
)
)
- mediaLoadingLogger.logMediaLoaded(
+ mediaLogger.logMediaLoaded(
mediaData.instanceId,
mediaData.active,
"reactivating media instead of smartspace"
@@ -226,7 +227,7 @@ constructor(
mediaFilterRepository.setRecommendationsLoadingState(
SmartspaceMediaLoadingModel.Loaded(key, shouldPrioritizeMutable)
)
- mediaLoadingLogger.logRecommendationLoaded(key, data.isActive, "loading recommendations")
+ mediaLogger.logRecommendationLoaded(key, data.isActive, "loading recommendations")
listeners.forEach { it.onSmartspaceMediaDataLoaded(key, data, shouldPrioritizeMutable) }
}
@@ -237,7 +238,7 @@ constructor(
mediaFilterRepository.addMediaDataLoadingState(
MediaDataLoadingModel.Removed(instanceId)
)
- mediaLoadingLogger.logMediaRemoved(instanceId, "removing media card")
+ mediaLogger.logMediaRemoved(instanceId, "removing media card")
// Only notify listeners if something actually changed
listeners.forEach { it.onMediaDataRemoved(key, userInitiated) }
}
@@ -253,11 +254,7 @@ constructor(
mediaFilterRepository.addMediaDataLoadingState(
MediaDataLoadingModel.Loaded(lastActiveId, immediately)
)
- mediaLoadingLogger.logMediaLoaded(
- lastActiveId,
- it.active,
- "expiring reactivated id"
- )
+ mediaLogger.logMediaLoaded(lastActiveId, it.active, "expiring reactivated id")
listeners.forEach { listener ->
getKey(lastActiveId)?.let { lastActiveKey ->
listener.onMediaDataLoaded(lastActiveKey, lastActiveKey, it, immediately)
@@ -278,11 +275,7 @@ constructor(
mediaFilterRepository.setRecommendationsLoadingState(
SmartspaceMediaLoadingModel.Removed(key, immediately)
)
- mediaLoadingLogger.logRecommendationRemoved(
- key,
- immediately,
- "removing recommendations card"
- )
+ mediaLogger.logRecommendationRemoved(key, immediately, "removing recommendations card")
listeners.forEach { it.onSmartspaceMediaDataRemoved(key, immediately) }
}
@@ -296,10 +289,7 @@ constructor(
mediaFilterRepository.addMediaDataLoadingState(
MediaDataLoadingModel.Removed(data.instanceId)
)
- mediaLoadingLogger.logMediaRemoved(
- data.instanceId,
- "Removing $key after profile change"
- )
+ mediaLogger.logMediaRemoved(data.instanceId, "Removing $key after profile change")
listeners.forEach { listener -> listener.onMediaDataRemoved(key, false) }
}
}
@@ -316,7 +306,7 @@ constructor(
mediaFilterRepository.addMediaDataLoadingState(
MediaDataLoadingModel.Removed(instanceId)
)
- mediaLoadingLogger.logMediaRemoved(instanceId, "Removing media after user change")
+ mediaLogger.logMediaRemoved(instanceId, "Removing media after user change")
getKey(instanceId)?.let {
listenersCopy.forEach { listener -> listener.onMediaDataRemoved(it, false) }
}
@@ -329,7 +319,7 @@ constructor(
MediaDataLoadingModel.Loaded(data.instanceId),
isUpdate
)
- mediaLoadingLogger.logMediaLoaded(
+ mediaLogger.logMediaLoaded(
data.instanceId,
data.active,
"Re-adding $key after user change"
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaLoadingLogger.kt b/packages/SystemUI/src/com/android/systemui/media/controls/shared/MediaLogger.kt
index c6cfd659eed5..2b710b5a67b7 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaLoadingLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/shared/MediaLogger.kt
@@ -14,18 +14,18 @@
* limitations under the License.
*/
-package com.android.systemui.media.controls.domain.pipeline
+package com.android.systemui.media.controls.shared
import com.android.internal.logging.InstanceId
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.core.LogLevel
-import com.android.systemui.log.dagger.MediaLoadingLog
+import com.android.systemui.log.dagger.MediaLog
import javax.inject.Inject
/** A buffered log for media loading events. */
@SysUISingleton
-class MediaLoadingLogger @Inject constructor(@MediaLoadingLog private val buffer: LogBuffer) {
+class MediaLogger @Inject constructor(@MediaLog private val buffer: LogBuffer) {
fun logMediaLoaded(instanceId: InstanceId, active: Boolean, reason: String) {
buffer.log(
@@ -78,7 +78,43 @@ class MediaLoadingLogger @Inject constructor(@MediaLoadingLog private val buffer
)
}
+ fun logMediaCardAdded(instanceId: InstanceId) {
+ buffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ { str1 = instanceId.toString() },
+ { "adding media card $str1 to carousel" }
+ )
+ }
+
+ fun logMediaCardRemoved(instanceId: InstanceId) {
+ buffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ { str1 = instanceId.toString() },
+ { "removing media card $str1 from carousel" }
+ )
+ }
+
+ fun logMediaRecommendationCardAdded(key: String) {
+ buffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ { str1 = key },
+ { "adding recommendation card $str1 to carousel" }
+ )
+ }
+
+ fun logMediaRecommendationCardRemoved(key: String) {
+ buffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ { str1 = key },
+ { "removing recommendation card $str1 from carousel" }
+ )
+ }
+
companion object {
- private const val TAG = "MediaLoadingLog"
+ private const val TAG = "MediaLog"
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt
index 125f97375fea..46c5c188344e 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt
@@ -662,13 +662,9 @@ constructor(
@VisibleForTesting
internal fun listenForAnyStateToGoneKeyguardTransition(scope: CoroutineScope): Job {
return scope.launch {
- if (SceneContainerFlag.isEnabled) {
- sceneInteractor.transitionState.filter { it.isIdle(Scenes.Gone) }
- } else {
- keyguardTransitionInteractor.transition(Edge.create(to = GONE)).filter {
- it.transitionState == TransitionState.FINISHED
- }
- }
+ keyguardTransitionInteractor
+ .isFinishedIn(scene = Scenes.Gone, stateWithoutSceneContainer = GONE)
+ .filter { it }
.collect {
showMediaCarousel()
updateHostVisibility()
@@ -849,8 +845,25 @@ constructor(
commonViewModels.addAll(viewModels)
// Ensure we only show the needed UMOs in media carousel.
- val viewSet = viewModels.toHashSet()
- controllerByViewModel.filter { !viewSet.contains(it.key) }.forEach { onRemoved(it.key) }
+ val viewIds =
+ viewModels
+ .map { mediaCommonViewModel ->
+ when (mediaCommonViewModel) {
+ is MediaCommonViewModel.MediaControl ->
+ mediaCommonViewModel.instanceId.toString()
+ is MediaCommonViewModel.MediaRecommendations -> mediaCommonViewModel.key
+ }
+ }
+ .toHashSet()
+ controllerByViewModel
+ .filter {
+ when (val viewModel = it.key) {
+ is MediaCommonViewModel.MediaControl ->
+ !viewIds.contains(viewModel.instanceId.toString())
+ is MediaCommonViewModel.MediaRecommendations -> !viewIds.contains(viewModel.key)
+ }
+ }
+ .forEach { onRemoved(it.key) }
}
private suspend fun getMediaLockScreenSetting(): Boolean {
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModel.kt
index c453a212a3cd..e7f7171d5be3 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModel.kt
@@ -23,6 +23,7 @@ import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.media.controls.domain.pipeline.interactor.MediaCarouselInteractor
import com.android.systemui.media.controls.domain.pipeline.interactor.factory.MediaControlInteractorFactory
+import com.android.systemui.media.controls.shared.MediaLogger
import com.android.systemui.media.controls.shared.model.MediaCommonModel
import com.android.systemui.media.controls.util.MediaFlags
import com.android.systemui.media.controls.util.MediaUiEventLogger
@@ -52,6 +53,7 @@ constructor(
private val recommendationsViewModel: MediaRecommendationsViewModel,
private val logger: MediaUiEventLogger,
private val mediaFlags: MediaFlags,
+ private val mediaLogger: MediaLogger,
) {
val mediaItems: StateFlow<List<MediaCommonViewModel>> =
@@ -131,10 +133,14 @@ constructor(
instanceId = instanceId,
immediatelyUpdateUi = commonModel.mediaLoadedModel.immediatelyUpdateUi,
controlViewModel = createMediaControlViewModel(instanceId),
- onAdded = { onMediaControlAddedOrUpdated(it, commonModel) },
+ onAdded = {
+ mediaLogger.logMediaCardAdded(instanceId)
+ onMediaControlAddedOrUpdated(it, commonModel)
+ },
onRemoved = {
interactor.removeMediaControl(instanceId, delay = 0L)
mediaControlByInstanceId.remove(instanceId)
+ mediaLogger.logMediaCardRemoved(instanceId)
},
onUpdated = { onMediaControlAddedOrUpdated(it, commonModel) },
isMediaFromRec = commonModel.isMediaFromRec,
@@ -168,6 +174,9 @@ constructor(
mediaFlags.isPersistentSsCardEnabled(),
recsViewModel = recommendationsViewModel,
onAdded = { commonViewModel ->
+ mediaLogger.logMediaRecommendationCardAdded(
+ commonModel.recsLoadingModel.key
+ )
onMediaRecommendationAddedOrUpdated(
commonViewModel as MediaCommonViewModel.MediaRecommendations
)
@@ -215,6 +224,7 @@ constructor(
commonModel: MediaCommonModel.MediaRecommendations,
immediatelyRemove: Boolean
) {
+ mediaLogger.logMediaRecommendationCardRemoved(commonModel.recsLoadingModel.key)
if (immediatelyRemove || isReorderingAllowed()) {
interactor.dismissSmartspaceRecommendation(commonModel.recsLoadingModel.key, 0L)
mediaRecs = null
diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleBackupHelper.java b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleBackupHelper.java
index d8c96dd182b4..eadbffe49495 100644
--- a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleBackupHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleBackupHelper.java
@@ -41,6 +41,8 @@ import android.preference.PreferenceManager;
import android.text.TextUtils;
import android.util.Log;
+import androidx.annotation.Nullable;
+
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.people.PeopleBackupFollowUpJob;
import com.android.systemui.people.SharedPreferencesHelper;
@@ -67,6 +69,7 @@ public class PeopleBackupHelper extends SharedPreferencesBackupHelper {
private final UserHandle mUserHandle;
private final PackageManager mPackageManager;
private final IPeopleManager mIPeopleManager;
+ @Nullable
private final AppWidgetManager mAppWidgetManager;
/**
@@ -404,6 +407,9 @@ public class PeopleBackupHelper extends SharedPreferencesBackupHelper {
private List<String> getExistingWidgetsForUser(int userId) {
List<String> existingWidgets = new ArrayList<>();
+ if (mAppWidgetManager == null) {
+ return existingWidgets;
+ }
int[] ids = mAppWidgetManager.getAppWidgetIds(
new ComponentName(mContext, PeopleSpaceWidgetProvider.class));
for (int id : ids) {
@@ -491,7 +497,11 @@ public class PeopleBackupHelper extends SharedPreferencesBackupHelper {
/** Sends a broadcast to update the existing Conversation widgets. */
public static void updateWidgets(Context context) {
- int[] widgetIds = AppWidgetManager.getInstance(context)
+ AppWidgetManager manager = AppWidgetManager.getInstance(context);
+ if (manager == null) {
+ return;
+ }
+ int[] widgetIds = manager
.getAppWidgetIds(new ComponentName(context, PeopleSpaceWidgetProvider.class));
if (DEBUG) {
for (int id : widgetIds) {
diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java
index 0a880293ca76..b0de80c8d7bb 100644
--- a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java
+++ b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java
@@ -140,7 +140,7 @@ public class PeopleSpaceWidgetManager implements Dumpable {
private final Object mLock = new Object();
private final Context mContext;
private LauncherApps mLauncherApps;
- private AppWidgetManager mAppWidgetManager;
+ private Optional<AppWidgetManager> mAppWidgetManagerOptional;
private IPeopleManager mIPeopleManager;
private SharedPreferences mSharedPrefs;
private PeopleManager mPeopleManager;
@@ -183,8 +183,9 @@ public class PeopleSpaceWidgetManager implements Dumpable {
};
@Inject
- public PeopleSpaceWidgetManager(Context context, LauncherApps launcherApps,
- CommonNotifCollection notifCollection,
+ public PeopleSpaceWidgetManager(Context context,
+ Optional<AppWidgetManager> appWidgetManagerOptional,
+ LauncherApps launcherApps, CommonNotifCollection notifCollection,
PackageManager packageManager, Optional<Bubbles> bubblesOptional,
UserManager userManager, NotificationManager notificationManager,
BroadcastDispatcher broadcastDispatcher, @Background Executor bgExecutor,
@@ -192,7 +193,7 @@ public class PeopleSpaceWidgetManager implements Dumpable {
@NonNull KeyguardUpdateMonitor keyguardUpdateMonitor) {
if (DEBUG) Log.d(TAG, "constructor");
mContext = context;
- mAppWidgetManager = AppWidgetManager.getInstance(context);
+ mAppWidgetManagerOptional = appWidgetManagerOptional;
mIPeopleManager = IPeopleManager.Stub.asInterface(
ServiceManager.getService(Context.PEOPLE_SERVICE));
mLauncherApps = launcherApps;
@@ -266,14 +267,14 @@ public class PeopleSpaceWidgetManager implements Dumpable {
*/
@VisibleForTesting
PeopleSpaceWidgetManager(Context context,
- AppWidgetManager appWidgetManager, IPeopleManager iPeopleManager,
+ Optional<AppWidgetManager> appWidgetManager, IPeopleManager iPeopleManager,
PeopleManager peopleManager, LauncherApps launcherApps,
CommonNotifCollection notifCollection, PackageManager packageManager,
Optional<Bubbles> bubblesOptional, UserManager userManager, BackupManager backupManager,
INotificationManager iNotificationManager, NotificationManager notificationManager,
@Background Executor executor, UserTracker userTracker) {
mContext = context;
- mAppWidgetManager = appWidgetManager;
+ mAppWidgetManagerOptional = appWidgetManager;
mIPeopleManager = iPeopleManager;
mPeopleManager = peopleManager;
mLauncherApps = launcherApps;
@@ -337,6 +338,10 @@ public class PeopleSpaceWidgetManager implements Dumpable {
/** Updates the current widget view with provided {@link PeopleSpaceTile}. */
private void updateAppWidgetViews(int appWidgetId, PeopleSpaceTile tile, Bundle options) {
+ if (mAppWidgetManagerOptional.isEmpty()) {
+ return;
+ }
+
PeopleTileKey key = getKeyFromStorageByWidgetId(appWidgetId);
if (DEBUG) Log.d(TAG, "Widget: " + appWidgetId + " for: " + key.toString());
@@ -349,7 +354,7 @@ public class PeopleSpaceWidgetManager implements Dumpable {
// Tell the AppWidgetManager to perform an update on the current app widget.
if (DEBUG) Log.d(TAG, "Calling update widget for widgetId: " + appWidgetId);
- mAppWidgetManager.updateAppWidget(appWidgetId, views);
+ mAppWidgetManagerOptional.get().updateAppWidget(appWidgetId, views);
}
/** Updates tile in app widget options and the current view. */
@@ -362,13 +367,17 @@ public class PeopleSpaceWidgetManager implements Dumpable {
/** Updates tile in app widget options and the current view. */
public void updateAppWidgetOptionsAndView(int appWidgetId, PeopleSpaceTile tile) {
+ if (mAppWidgetManagerOptional.isEmpty()) {
+ return;
+ }
+
if (tile == null) {
Log.w(TAG, "Storing null tile for widget " + appWidgetId);
}
synchronized (mTiles) {
mTiles.put(appWidgetId, tile);
}
- Bundle options = mAppWidgetManager.getAppWidgetOptions(appWidgetId);
+ Bundle options = mAppWidgetManagerOptional.get().getAppWidgetOptions(appWidgetId);
updateAppWidgetViews(appWidgetId, tile, options);
}
@@ -484,6 +493,10 @@ public class PeopleSpaceWidgetManager implements Dumpable {
private void updateWidgetsWithNotificationChangedInBackground(StatusBarNotification sbn,
PeopleSpaceUtils.NotificationAction action,
Collection<NotificationEntry> notifications) {
+ if (mAppWidgetManagerOptional.isEmpty()) {
+ return;
+ }
+
try {
PeopleTileKey key = new PeopleTileKey(
sbn.getShortcutId(), sbn.getUser().getIdentifier(), sbn.getPackageName());
@@ -491,7 +504,7 @@ public class PeopleSpaceWidgetManager implements Dumpable {
if (DEBUG) Log.d(TAG, "Sbn doesn't contain valid PeopleTileKey: " + key.toString());
return;
}
- int[] widgetIds = mAppWidgetManager.getAppWidgetIds(
+ int[] widgetIds = mAppWidgetManagerOptional.get().getAppWidgetIds(
new ComponentName(mContext, PeopleSpaceWidgetProvider.class)
);
if (widgetIds.length == 0) {
@@ -807,10 +820,14 @@ public class PeopleSpaceWidgetManager implements Dumpable {
UserHandle user,
NotificationChannel channel,
int modificationType) {
+ if (mAppWidgetManagerOptional.isEmpty()) {
+ return;
+ }
+
if (channel.isConversation()) {
mBgExecutor.execute(() -> {
if (mUserManager.isUserUnlocked(user)) {
- updateWidgets(mAppWidgetManager.getAppWidgetIds(
+ updateWidgets(mAppWidgetManagerOptional.get().getAppWidgetIds(
new ComponentName(mContext, PeopleSpaceWidgetProvider.class)
));
}
@@ -829,13 +846,18 @@ public class PeopleSpaceWidgetManager implements Dumpable {
// learning about the widget. If so, the widget adder should have populated options with
// PeopleTileKey arguments.
if (DEBUG) Log.d(TAG, "onAppWidgetOptionsChanged called for widget: " + appWidgetId);
+ if (mAppWidgetManagerOptional.isEmpty()) {
+ return;
+ }
+
PeopleTileKey optionsKey = AppWidgetOptionsHelper.getPeopleTileKeyFromBundle(newOptions);
if (PeopleTileKey.isValid(optionsKey)) {
if (DEBUG) {
Log.d(TAG, "PeopleTileKey was present in Options, shortcutId: "
+ optionsKey.getShortcutId());
}
- AppWidgetOptionsHelper.removePeopleTileKey(mAppWidgetManager, appWidgetId);
+ AppWidgetOptionsHelper.removePeopleTileKey(mAppWidgetManagerOptional.get(),
+ appWidgetId);
addNewWidget(appWidgetId, optionsKey);
}
// Update views for new widget dimensions.
@@ -1004,6 +1026,10 @@ public class PeopleSpaceWidgetManager implements Dumpable {
public boolean requestPinAppWidget(ShortcutInfo shortcutInfo, Bundle options) {
if (DEBUG) Log.d(TAG, "Requesting pin widget, shortcutId: " + shortcutInfo.getId());
+ if (mAppWidgetManagerOptional.isEmpty()) {
+ return false;
+ }
+
RemoteViews widgetPreview = getPreview(shortcutInfo.getId(),
shortcutInfo.getUserHandle(), shortcutInfo.getPackage(), options);
if (widgetPreview == null) {
@@ -1017,7 +1043,8 @@ public class PeopleSpaceWidgetManager implements Dumpable {
PeopleSpaceWidgetPinnedReceiver.getPendingIntent(mContext, shortcutInfo);
ComponentName componentName = new ComponentName(mContext, PeopleSpaceWidgetProvider.class);
- return mAppWidgetManager.requestPinAppWidget(componentName, extras, successCallback);
+ return mAppWidgetManagerOptional.get().requestPinAppWidget(componentName, extras,
+ successCallback);
}
/** Returns a list of map entries corresponding to user's priority conversations. */
@@ -1104,7 +1131,11 @@ public class PeopleSpaceWidgetManager implements Dumpable {
/** Updates any app widget to the current state, triggered by a broadcast update. */
@VisibleForTesting
void updateWidgetsFromBroadcastInBackground(String entryPoint) {
- int[] appWidgetIds = mAppWidgetManager.getAppWidgetIds(
+ if (mAppWidgetManagerOptional.isEmpty()) {
+ return;
+ }
+
+ int[] appWidgetIds = mAppWidgetManagerOptional.get().getAppWidgetIds(
new ComponentName(mContext, PeopleSpaceWidgetProvider.class));
if (appWidgetIds == null) {
return;
@@ -1272,13 +1303,17 @@ public class PeopleSpaceWidgetManager implements Dumpable {
remapSharedFile(widgets);
remapFollowupFile(widgets);
- int[] widgetIds = mAppWidgetManager.getAppWidgetIds(
+ if (mAppWidgetManagerOptional.isEmpty()) {
+ return;
+ }
+
+ int[] widgetIds = mAppWidgetManagerOptional.get().getAppWidgetIds(
new ComponentName(mContext, PeopleSpaceWidgetProvider.class));
Bundle b = new Bundle();
b.putBoolean(AppWidgetManager.OPTION_APPWIDGET_RESTORE_COMPLETED, true);
for (int id : widgetIds) {
if (DEBUG) Log.d(TAG, "Setting widget as restored, widget id:" + id);
- mAppWidgetManager.updateAppWidgetOptions(id, b);
+ mAppWidgetManagerOptional.get().updateAppWidgetOptions(id, b);
}
updateWidgets(widgetIds);
@@ -1437,14 +1472,15 @@ public class PeopleSpaceWidgetManager implements Dumpable {
@VisibleForTesting
void updateGeneratedPreviewForUser(UserHandle user) {
if (!generatedPreviews() || mUpdatedPreviews.get(user.getIdentifier())
- || !mUserManager.isUserUnlocked(user)) {
+ || !mUserManager.isUserUnlocked(user) || mAppWidgetManagerOptional.isEmpty()) {
return;
}
// The widget provider may be disabled on SystemUI implementers, e.g. TvSystemUI.
ComponentName provider = new ComponentName(mContext, PeopleSpaceWidgetProvider.class);
- List<AppWidgetProviderInfo> infos = mAppWidgetManager.getInstalledProvidersForPackage(
- mContext.getPackageName(), user);
+ List<AppWidgetProviderInfo> infos =
+ mAppWidgetManagerOptional.get().getInstalledProvidersForPackage(
+ mContext.getPackageName(), user);
if (infos.stream().noneMatch(info -> info.provider.equals(provider))) {
return;
}
@@ -1452,7 +1488,7 @@ public class PeopleSpaceWidgetManager implements Dumpable {
if (DEBUG) {
Log.d(TAG, "Updating People Space widget preview for user " + user.getIdentifier());
}
- boolean success = mAppWidgetManager.setWidgetPreview(
+ boolean success = mAppWidgetManagerOptional.get().setWidgetPreview(
provider, WIDGET_CATEGORY_HOME_SCREEN | WIDGET_CATEGORY_KEYGUARD,
new RemoteViews(mContext.getPackageName(),
R.layout.people_space_placeholder_layout));
diff --git a/packages/SystemUI/src/com/android/systemui/qs/ReduceBrightColorsController.java b/packages/SystemUI/src/com/android/systemui/qs/ReduceBrightColorsController.java
index 10c8e530553a..cf1dca3cbb23 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/ReduceBrightColorsController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/ReduceBrightColorsController.java
@@ -16,6 +16,8 @@
package com.android.systemui.qs;
+import android.content.res.Resources;
+
import com.android.systemui.statusbar.policy.CallbackController;
public interface ReduceBrightColorsController extends
@@ -27,6 +29,14 @@ public interface ReduceBrightColorsController extends
/** Sets the activation state of Reduce Bright Colors */
void setReduceBrightColorsActivated(boolean activated);
+ /** Sets whether Reduce Bright Colors is enabled */
+ void setReduceBrightColorsFeatureAvailable(boolean enabled);
+
+ /** Gets whether Reduce Bright Colors is enabled */
+ boolean isReduceBrightColorsFeatureAvailable();
+
+ /** Gets whether Reduce Bright Colors is being transitioned to Even Dimmer */
+ boolean isInUpgradeMode(Resources resources);
/**
* Listener invoked whenever the Reduce Bright Colors settings are changed.
*/
@@ -38,5 +48,12 @@ public interface ReduceBrightColorsController extends
*/
default void onActivated(boolean activated) {
}
+ /**
+ * Listener invoked when the feature enabled state changes.
+ *
+ * @param enabled {@code true} if Reduce Bright Colors feature is enabled.
+ */
+ default void onFeatureEnabledChanged(boolean enabled) {
+ }
}
} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/ReduceBrightColorsControllerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/ReduceBrightColorsControllerImpl.java
index 846d63f10875..d68b22b84f09 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/ReduceBrightColorsControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/ReduceBrightColorsControllerImpl.java
@@ -19,6 +19,7 @@
package com.android.systemui.qs;
import android.content.Context;
+import android.content.res.Resources;
import android.database.ContentObserver;
import android.hardware.display.ColorDisplayManager;
import android.net.Uri;
@@ -28,6 +29,7 @@ import android.provider.Settings;
import androidx.annotation.NonNull;
+import com.android.server.display.feature.flags.Flags;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.settings.UserTracker;
@@ -47,6 +49,7 @@ public class ReduceBrightColorsControllerImpl implements
private final ContentObserver mContentObserver;
private final SecureSettings mSecureSettings;
private final ArrayList<ReduceBrightColorsController.Listener> mListeners = new ArrayList<>();
+ private boolean mAvailable = true;
@Inject
public ReduceBrightColorsControllerImpl(UserTracker userTracker,
@@ -75,6 +78,7 @@ public class ReduceBrightColorsControllerImpl implements
mCurrentUserTrackerCallback = new UserTracker.Callback() {
@Override
public void onUserChanged(int newUser, Context userContext) {
+ mAvailable = true;
synchronized (mListeners) {
if (mListeners.size() > 0) {
mSecureSettings.unregisterContentObserverSync(mContentObserver);
@@ -121,10 +125,35 @@ public class ReduceBrightColorsControllerImpl implements
mManager.setReduceBrightColorsActivated(activated);
}
+ @Override
+ public void setReduceBrightColorsFeatureAvailable(boolean enabled) {
+ mAvailable = enabled;
+ dispatchOnEnabledChanged(enabled);
+ mAvailable = true;
+ }
+
+ @Override
+ public boolean isReduceBrightColorsFeatureAvailable() {
+ return mAvailable;
+ }
+
+ @Override
+ public boolean isInUpgradeMode(Resources resources) {
+ return Flags.evenDimmer() && resources.getBoolean(
+ com.android.internal.R.bool.config_evenDimmerEnabled);
+ }
+
private void dispatchOnActivated(boolean activated) {
ArrayList<Listener> copy = new ArrayList<>(mListeners);
for (Listener l : copy) {
l.onActivated(activated);
}
}
+
+ private void dispatchOnEnabledChanged(boolean enabled) {
+ ArrayList<Listener> copy = new ArrayList<>(mListeners);
+ for (Listener l : copy) {
+ l.onFeatureEnabledChanged(enabled);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/SettingObserver.java b/packages/SystemUI/src/com/android/systemui/qs/SettingObserver.java
index 6092348b964e..2287f4d68933 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/SettingObserver.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/SettingObserver.java
@@ -19,6 +19,7 @@ package com.android.systemui.qs;
import android.database.ContentObserver;
import android.os.Handler;
+import com.android.systemui.Flags;
import com.android.systemui.statusbar.policy.Listenable;
import com.android.systemui.util.settings.SecureSettings;
import com.android.systemui.util.settings.SettingsProxy;
@@ -74,10 +75,20 @@ public abstract class SettingObserver extends ContentObserver implements Listena
mListening = listening;
if (listening) {
mObservedValue = getValueFromProvider();
- mSettingsProxy.registerContentObserverSync(
- mSettingsProxy.getUriFor(mSettingName), false, this);
+ if (Flags.qsRegisterSettingObserverOnBgThread()) {
+ mSettingsProxy.registerContentObserverAsync(
+ mSettingsProxy.getUriFor(mSettingName), false, this,
+ () -> mObservedValue = getValueFromProvider());
+ } else {
+ mSettingsProxy.registerContentObserverSync(
+ mSettingsProxy.getUriFor(mSettingName), false, this);
+ }
} else {
- mSettingsProxy.unregisterContentObserverSync(this);
+ if (Flags.qsRegisterSettingObserverOnBgThread()) {
+ mSettingsProxy.unregisterContentObserverAsync(this);
+ } else {
+ mSettingsProxy.unregisterContentObserverSync(this);
+ }
mObservedValue = mDefaultValue;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
index a45d6f63cd81..89f85ab14dd6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
@@ -32,6 +32,7 @@ import android.widget.Button;
import androidx.annotation.Nullable;
+import com.android.server.display.feature.flags.Flags;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.qs.QSTile;
@@ -116,6 +117,10 @@ public class TileQueryHelper {
final ArrayList<QSTile> tilesToAdd = new ArrayList<>();
possibleTiles.remove("cell");
possibleTiles.remove("wifi");
+ if (Flags.evenDimmer() && mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_evenDimmerEnabled)) {
+ possibleTiles.remove("reduce_brightness");
+ }
for (String spec : possibleTiles) {
// Only add current and stock tiles that can be created from QSFactoryImpl.
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/dagger/PanelsModule.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/dagger/PanelsModule.kt
index ff20707c1922..78f4b4b32237 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/dagger/PanelsModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/dagger/PanelsModule.kt
@@ -19,18 +19,17 @@ package com.android.systemui.qs.panels.dagger
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.LogBufferFactory
+import com.android.systemui.qs.panels.data.repository.DefaultLargeTilesRepository
+import com.android.systemui.qs.panels.data.repository.DefaultLargeTilesRepositoryImpl
import com.android.systemui.qs.panels.data.repository.GridLayoutTypeRepository
import com.android.systemui.qs.panels.data.repository.GridLayoutTypeRepositoryImpl
-import com.android.systemui.qs.panels.data.repository.IconTilesRepository
-import com.android.systemui.qs.panels.data.repository.IconTilesRepositoryImpl
import com.android.systemui.qs.panels.domain.interactor.GridTypeConsistencyInteractor
import com.android.systemui.qs.panels.domain.interactor.InfiniteGridConsistencyInteractor
import com.android.systemui.qs.panels.domain.interactor.NoopGridConsistencyInteractor
-import com.android.systemui.qs.panels.shared.model.GridConsistencyLog
import com.android.systemui.qs.panels.shared.model.GridLayoutType
-import com.android.systemui.qs.panels.shared.model.IconLabelVisibilityLog
import com.android.systemui.qs.panels.shared.model.InfiniteGridLayoutType
import com.android.systemui.qs.panels.shared.model.PaginatedGridLayoutType
+import com.android.systemui.qs.panels.shared.model.PanelsLog
import com.android.systemui.qs.panels.shared.model.PartitionedGridLayoutType
import com.android.systemui.qs.panels.shared.model.StretchedGridLayoutType
import com.android.systemui.qs.panels.ui.compose.GridLayout
@@ -53,7 +52,10 @@ import javax.inject.Named
@Module
interface PanelsModule {
- @Binds fun bindIconTilesRepository(impl: IconTilesRepositoryImpl): IconTilesRepository
+ @Binds
+ fun bindDefaultLargeTilesSpecsRepository(
+ impl: DefaultLargeTilesRepositoryImpl
+ ): DefaultLargeTilesRepository
@Binds
fun bindGridLayoutTypeRepository(impl: GridLayoutTypeRepositoryImpl): GridLayoutTypeRepository
@@ -87,16 +89,9 @@ interface PanelsModule {
companion object {
@Provides
@SysUISingleton
- @GridConsistencyLog
- fun providesGridConsistencyLog(factory: LogBufferFactory): LogBuffer {
- return factory.create("GridConsistencyLog", 50)
- }
-
- @Provides
- @SysUISingleton
- @IconLabelVisibilityLog
- fun providesIconTileLabelVisibilityLog(factory: LogBufferFactory): LogBuffer {
- return factory.create("IconLabelVisibilityLog", 50)
+ @PanelsLog
+ fun providesPanelsLog(factory: LogBufferFactory): LogBuffer {
+ return factory.create("PanelsLog", 50)
}
@Provides
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/IconTilesRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/DefaultLargeTilesRepository.kt
index 095bdf2ff5bd..9a1671df60e9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/IconTilesRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/DefaultLargeTilesRepository.kt
@@ -20,25 +20,18 @@ import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.qs.pipeline.shared.TileSpec
import javax.inject.Inject
-/** Repository for checking if a tile should be displayed as an icon. */
-interface IconTilesRepository {
- fun isIconTile(spec: TileSpec): Boolean
+/** Repository for the default set of [TileSpec] that should be displayed as large tiles. */
+interface DefaultLargeTilesRepository {
+ val defaultLargeTiles: Set<TileSpec>
}
@SysUISingleton
-class IconTilesRepositoryImpl @Inject constructor() : IconTilesRepository {
-
- override fun isIconTile(spec: TileSpec): Boolean {
- return !LARGE_TILES.contains(spec)
- }
-
- companion object {
- private val LARGE_TILES =
- setOf(
- TileSpec.create("internet"),
- TileSpec.create("bt"),
- TileSpec.create("dnd"),
- TileSpec.create("cast"),
- )
- }
+class DefaultLargeTilesRepositoryImpl @Inject constructor() : DefaultLargeTilesRepository {
+ override val defaultLargeTiles =
+ setOf(
+ TileSpec.create("internet"),
+ TileSpec.create("bt"),
+ TileSpec.create("dnd"),
+ TileSpec.create("cast"),
+ )
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/QSPreferencesRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/QSPreferencesRepository.kt
index f3e5b8f0c214..971598dea0bd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/QSPreferencesRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/QSPreferencesRepository.kt
@@ -20,6 +20,7 @@ import android.content.Context
import android.content.SharedPreferences
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.qs.pipeline.shared.TileSpec
import com.android.systemui.settings.UserFileManager
import com.android.systemui.user.data.repository.UserRepository
import com.android.systemui.util.kotlin.SharedPreferencesExt.observe
@@ -40,6 +41,7 @@ class QSPreferencesRepository
constructor(
private val userFileManager: UserFileManager,
private val userRepository: UserRepository,
+ private val defaultLargeTilesRepository: DefaultLargeTilesRepository,
@Background private val backgroundDispatcher: CoroutineDispatcher,
) {
/** Whether to show the labels on icon tiles for the current user. */
@@ -51,6 +53,23 @@ constructor(
}
.flowOn(backgroundDispatcher)
+ /** Set of [TileSpec] to display as large tiles for the current user. */
+ val largeTilesSpecs: Flow<Set<TileSpec>> =
+ userRepository.selectedUserInfo
+ .flatMapLatest { userInfo ->
+ val prefs = getSharedPrefs(userInfo.id)
+ prefs.observe().emitOnStart().map {
+ prefs
+ .getStringSet(
+ LARGE_TILES_SPECS_KEY,
+ defaultLargeTilesRepository.defaultLargeTiles.map { it.spec }.toSet()
+ )
+ ?.map { TileSpec.create(it) }
+ ?.toSet() ?: defaultLargeTilesRepository.defaultLargeTiles
+ }
+ }
+ .flowOn(backgroundDispatcher)
+
/** Sets for the current user whether to show the labels on icon tiles. */
fun setShowLabels(showLabels: Boolean) {
with(getSharedPrefs(userRepository.getSelectedUserInfo().id)) {
@@ -58,6 +77,13 @@ constructor(
}
}
+ /** Sets for the current user the set of [TileSpec] to display as large tiles. */
+ fun setLargeTilesSpecs(specs: Set<TileSpec>) {
+ with(getSharedPrefs(userRepository.getSelectedUserInfo().id)) {
+ edit().putStringSet(LARGE_TILES_SPECS_KEY, specs.map { it.spec }.toSet()).apply()
+ }
+ }
+
private fun getSharedPrefs(userId: Int): SharedPreferences {
return userFileManager.getSharedPreferences(
FILE_NAME,
@@ -68,6 +94,7 @@ constructor(
companion object {
private const val ICON_LABELS_KEY = "show_icon_labels"
+ private const val LARGE_TILES_SPECS_KEY = "large_tiles_specs"
const val FILE_NAME = "quick_settings_prefs"
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/StockTilesRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/StockTilesRepository.kt
index ec9d151a26d3..86a29f91e51c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/StockTilesRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/StockTilesRepository.kt
@@ -17,6 +17,7 @@
package com.android.systemui.qs.panels.data.repository
import android.content.res.Resources
+import com.android.server.display.feature.flags.Flags
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.qs.pipeline.shared.TileSpec
@@ -32,10 +33,15 @@ constructor(
/**
* List of stock platform tiles. All of the specs will be of type [TileSpec.PlatformTileSpec].
*/
+ val shouldRemoveRbcTile: Boolean =
+ Flags.evenDimmer() &&
+ resources.getBoolean(com.android.internal.R.bool.config_evenDimmerEnabled)
+
val stockTiles =
resources
.getString(R.string.quick_settings_tiles_stock)
.split(",")
+ .filterNot { shouldRemoveRbcTile && it.equals("reduce_brightness") }
.map(TileSpec::create)
.filterNot { it is TileSpec.Invalid }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/GridConsistencyInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/GridConsistencyInteractor.kt
index 7732092d6bcf..a2e7ea6fe797 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/GridConsistencyInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/GridConsistencyInteractor.kt
@@ -20,8 +20,8 @@ import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.core.LogLevel
-import com.android.systemui.qs.panels.shared.model.GridConsistencyLog
import com.android.systemui.qs.panels.shared.model.GridLayoutType
+import com.android.systemui.qs.panels.shared.model.PanelsLog
import com.android.systemui.qs.pipeline.domain.interactor.CurrentTilesInteractor
import com.android.systemui.qs.pipeline.shared.TileSpec
import javax.inject.Inject
@@ -39,7 +39,7 @@ constructor(
private val consistencyInteractors:
Map<GridLayoutType, @JvmSuppressWildcards GridTypeConsistencyInteractor>,
private val defaultConsistencyInteractor: GridTypeConsistencyInteractor,
- @GridConsistencyLog private val logBuffer: LogBuffer,
+ @PanelsLog private val logBuffer: LogBuffer,
@Application private val applicationScope: CoroutineScope,
) {
fun start() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/IconLabelVisibilityInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/IconLabelVisibilityInteractor.kt
index 6a899b07b2a0..fe4012787394 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/IconLabelVisibilityInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/IconLabelVisibilityInteractor.kt
@@ -20,7 +20,7 @@ import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.core.LogLevel
-import com.android.systemui.qs.panels.shared.model.IconLabelVisibilityLog
+import com.android.systemui.qs.panels.shared.model.PanelsLog
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.SharingStarted
@@ -33,7 +33,7 @@ class IconLabelVisibilityInteractor
@Inject
constructor(
private val preferencesInteractor: QSPreferencesInteractor,
- @IconLabelVisibilityLog private val logBuffer: LogBuffer,
+ @PanelsLog private val logBuffer: LogBuffer,
@Application scope: CoroutineScope,
) {
val showLabels: StateFlow<Boolean> =
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/IconTilesInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/IconTilesInteractor.kt
index 524ea8b70100..b18358cedde7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/IconTilesInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/IconTilesInteractor.kt
@@ -17,12 +17,54 @@
package com.android.systemui.qs.panels.domain.interactor
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.qs.panels.data.repository.IconTilesRepository
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.core.LogLevel
+import com.android.systemui.qs.panels.data.repository.DefaultLargeTilesRepository
+import com.android.systemui.qs.panels.shared.model.PanelsLog
import com.android.systemui.qs.pipeline.shared.TileSpec
import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.flow.stateIn
-/** Interactor for retrieving the list of [TileSpec] to be displayed as icons. */
+/** Interactor for retrieving the list of [TileSpec] to be displayed as icons and resizing icons. */
@SysUISingleton
-class IconTilesInteractor @Inject constructor(private val repo: IconTilesRepository) {
- fun isIconTile(spec: TileSpec): Boolean = repo.isIconTile(spec)
+class IconTilesInteractor
+@Inject
+constructor(
+ repo: DefaultLargeTilesRepository,
+ private val preferencesInteractor: QSPreferencesInteractor,
+ @PanelsLog private val logBuffer: LogBuffer,
+ @Application private val applicationScope: CoroutineScope
+) {
+
+ private val largeTilesSpecs =
+ preferencesInteractor.largeTilesSpecs
+ .onEach { logChange(it) }
+ .stateIn(applicationScope, SharingStarted.Eagerly, repo.defaultLargeTiles)
+
+ fun isIconTile(spec: TileSpec): Boolean = !largeTilesSpecs.value.contains(spec)
+
+ fun resize(spec: TileSpec, toIcon: Boolean) {
+ if (toIcon) {
+ preferencesInteractor.setLargeTilesSpecs(largeTilesSpecs.value - spec)
+ } else {
+ preferencesInteractor.setLargeTilesSpecs(largeTilesSpecs.value + spec)
+ }
+ }
+
+ private fun logChange(specs: Set<TileSpec>) {
+ logBuffer.log(
+ LOG_BUFFER_LARGE_TILES_SPECS_CHANGE_TAG,
+ LogLevel.DEBUG,
+ { str1 = specs.toString() },
+ { "Large tiles change: $str1" }
+ )
+ }
+
+ private companion object {
+ const val LOG_BUFFER_LARGE_TILES_SPECS_CHANGE_TAG = "LargeTilesSpecsChange"
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/QSPreferencesInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/QSPreferencesInteractor.kt
index 811be80d23fa..854e23f16a13 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/QSPreferencesInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/QSPreferencesInteractor.kt
@@ -18,14 +18,20 @@ package com.android.systemui.qs.panels.domain.interactor
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.qs.panels.data.repository.QSPreferencesRepository
+import com.android.systemui.qs.pipeline.shared.TileSpec
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
@SysUISingleton
class QSPreferencesInteractor @Inject constructor(private val repo: QSPreferencesRepository) {
val showLabels: Flow<Boolean> = repo.showLabels
+ val largeTilesSpecs: Flow<Set<TileSpec>> = repo.largeTilesSpecs
fun setShowLabels(showLabels: Boolean) {
repo.setShowLabels(showLabels)
}
+
+ fun setLargeTilesSpecs(specs: Set<TileSpec>) {
+ repo.setLargeTilesSpecs(specs)
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/shared/model/GridConsistencyLog.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/shared/model/PanelsLog.kt
index 884cde35a1aa..50cb3869f79e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/shared/model/GridConsistencyLog.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/shared/model/PanelsLog.kt
@@ -18,7 +18,4 @@ package com.android.systemui.qs.panels.shared.model
import javax.inject.Qualifier
-@Qualifier
-@MustBeDocumented
-@Retention(AnnotationRetention.RUNTIME)
-annotation class GridConsistencyLog()
+@Qualifier @MustBeDocumented @Retention(AnnotationRetention.RUNTIME) annotation class PanelsLog()
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/DragAndDropState.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/DragAndDropState.kt
index 007ec3a911e1..295a998e7500 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/DragAndDropState.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/DragAndDropState.kt
@@ -149,11 +149,13 @@ fun Modifier.dragAndDropTileList(
fun Modifier.dragAndDropTileSource(
tileSpec: TileSpec,
onTap: (TileSpec) -> Unit,
+ onDoubleTap: (TileSpec) -> Unit,
dragAndDropState: DragAndDropState
): Modifier {
return dragAndDropSource {
detectTapGestures(
onTap = { onTap(tileSpec) },
+ onDoubleTap = { onDoubleTap(tileSpec) },
onLongPress = {
dragAndDropState.onStarted(tileSpec)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/InfiniteGridLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/InfiniteGridLayout.kt
index ea97f0de2bb8..ada774db1c6e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/InfiniteGridLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/InfiniteGridLayout.kt
@@ -22,6 +22,7 @@ import androidx.compose.foundation.lazy.grid.GridItemSpan
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.getValue
+import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.dimensionResource
import androidx.lifecycle.compose.collectAsStateWithLifecycle
@@ -76,14 +77,18 @@ constructor(
onRemoveTile: (TileSpec) -> Unit,
) {
val columns by gridSizeViewModel.columns.collectAsStateWithLifecycle()
+ val isIcon: (TileSpec) -> Boolean by rememberUpdatedState { tileSpec ->
+ iconTilesViewModel.isIconTile(tileSpec)
+ }
DefaultEditTileGrid(
tiles = tiles,
- isIconOnly = iconTilesViewModel::isIconTile,
+ isIconOnly = isIcon,
columns = GridCells.Fixed(columns),
modifier = modifier,
onAddTile = onAddTile,
onRemoveTile = onRemoveTile,
+ onResize = iconTilesViewModel::resize,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PartitionedGridLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PartitionedGridLayout.kt
index 092ad44d289b..8ca91d89439b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PartitionedGridLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PartitionedGridLayout.kt
@@ -122,6 +122,9 @@ class PartitionedGridLayout @Inject constructor(private val viewModel: Partition
val addTileToEnd: (TileSpec) -> Unit by rememberUpdatedState {
onAddTile(it, CurrentTilesInteractor.POSITION_AT_END)
}
+ val onDoubleTap: (TileSpec) -> Unit by rememberUpdatedState { tileSpec ->
+ viewModel.resize(tileSpec, !viewModel.isIconTile(tileSpec))
+ }
val largeTileHeight = tileHeight()
val iconTileHeight = tileHeight(showLabels)
val tilePadding = dimensionResource(R.dimen.qs_tile_margin_vertical)
@@ -161,6 +164,7 @@ class PartitionedGridLayout @Inject constructor(private val viewModel: Partition
tilePadding = tilePadding,
onAdd = onAddTile,
onRemove = onRemoveTile,
+ onDoubleTap = onDoubleTap,
isIconOnly = viewModel::isIconTile,
columns = columns,
showLabels = showLabels,
@@ -173,6 +177,7 @@ class PartitionedGridLayout @Inject constructor(private val viewModel: Partition
tilePadding = tilePadding,
addTileToEnd = addTileToEnd,
onRemove = onRemoveTile,
+ onDoubleTap = onDoubleTap,
isIconOnly = viewModel::isIconTile,
showLabels = showLabels,
columns = columns,
@@ -203,6 +208,7 @@ class PartitionedGridLayout @Inject constructor(private val viewModel: Partition
tilePadding: Dp,
onAdd: (TileSpec, Int) -> Unit,
onRemove: (TileSpec) -> Unit,
+ onDoubleTap: (TileSpec) -> Unit,
isIconOnly: (TileSpec) -> Boolean,
showLabels: Boolean,
columns: Int,
@@ -224,6 +230,7 @@ class PartitionedGridLayout @Inject constructor(private val viewModel: Partition
tiles = largeTiles,
clickAction = ClickAction.REMOVE,
onClick = onRemove,
+ onDoubleTap = onDoubleTap,
isIconOnly = { false },
dragAndDropState = dragAndDropState,
acceptDrops = { !isIconOnly(it) },
@@ -244,6 +251,7 @@ class PartitionedGridLayout @Inject constructor(private val viewModel: Partition
tiles = smallTiles,
clickAction = ClickAction.REMOVE,
onClick = onRemove,
+ onDoubleTap = onDoubleTap,
isIconOnly = { true },
showLabels = showLabels,
dragAndDropState = dragAndDropState,
@@ -263,6 +271,7 @@ class PartitionedGridLayout @Inject constructor(private val viewModel: Partition
tilePadding: Dp,
addTileToEnd: (TileSpec) -> Unit,
onRemove: (TileSpec) -> Unit,
+ onDoubleTap: (TileSpec) -> Unit,
isIconOnly: (TileSpec) -> Boolean,
showLabels: Boolean,
columns: Int,
@@ -296,6 +305,7 @@ class PartitionedGridLayout @Inject constructor(private val viewModel: Partition
largeTiles,
ClickAction.ADD,
addTileToEnd,
+ onDoubleTap,
isIconOnly,
dragAndDropState,
acceptDrops = { true },
@@ -308,6 +318,7 @@ class PartitionedGridLayout @Inject constructor(private val viewModel: Partition
smallTiles,
ClickAction.ADD,
addTileToEnd,
+ onDoubleTap,
isIconOnly,
showLabels = showLabels,
dragAndDropState = dragAndDropState,
@@ -321,6 +332,7 @@ class PartitionedGridLayout @Inject constructor(private val viewModel: Partition
tilesCustom,
ClickAction.ADD,
addTileToEnd,
+ onDoubleTap,
isIconOnly,
showLabels = showLabels,
dragAndDropState = dragAndDropState,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/StretchedGridLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/StretchedGridLayout.kt
index 4a9010270ac5..770d44124025 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/StretchedGridLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/StretchedGridLayout.kt
@@ -104,6 +104,7 @@ constructor(
modifier = modifier,
onAddTile = onAddTile,
onRemoveTile = onRemoveTile,
+ onResize = iconTilesViewModel::resize,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/Tile.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/Tile.kt
index 0bb4cfa327a9..3fdd7f769cf3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/Tile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/Tile.kt
@@ -81,7 +81,6 @@ import com.android.systemui.common.ui.compose.Icon
import com.android.systemui.common.ui.compose.load
import com.android.systemui.plugins.qs.QSTile
import com.android.systemui.qs.panels.ui.viewmodel.EditTileViewModel
-import com.android.systemui.qs.panels.ui.viewmodel.TileUiState
import com.android.systemui.qs.panels.ui.viewmodel.TileViewModel
import com.android.systemui.qs.panels.ui.viewmodel.toUiState
import com.android.systemui.qs.pipeline.domain.interactor.CurrentTilesInteractor
@@ -91,7 +90,6 @@ import com.android.systemui.res.R
import java.util.function.Supplier
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.delay
-import kotlinx.coroutines.flow.mapLatest
object TileType
@@ -103,29 +101,27 @@ fun Tile(
showLabels: Boolean = false,
modifier: Modifier,
) {
- val state: TileUiState by
- tile.state
- .mapLatest { it.toUiState() }
- .collectAsStateWithLifecycle(tile.currentState.toUiState())
- val colors = TileDefaults.getColorForState(state.state)
+ val state by tile.state.collectAsStateWithLifecycle(tile.currentState)
+ val uiState = remember(state) { state.toUiState() }
+ val colors = TileDefaults.getColorForState(uiState.state)
TileContainer(
colors = colors,
showLabels = showLabels,
- label = state.label.toString(),
+ label = uiState.label,
iconOnly = iconOnly,
clickEnabled = true,
onClick = tile::onClick,
onLongClick = tile::onLongClick,
modifier = modifier,
) {
- val icon = getTileIcon(icon = state.icon)
+ val icon = getTileIcon(icon = uiState.icon)
if (iconOnly) {
TileIcon(icon = icon, color = colors.icon, modifier = Modifier.align(Alignment.Center))
} else {
LargeTileContent(
- label = state.label.toString(),
- secondaryLabel = state.secondaryLabel.toString(),
+ label = uiState.label,
+ secondaryLabel = uiState.secondaryLabel,
icon = icon,
colors = colors,
clickEnabled = true,
@@ -234,19 +230,26 @@ private fun LargeTileContent(
Text(
label,
color = colors.label,
- modifier = Modifier.basicMarquee(),
+ modifier = Modifier.tileMarquee(),
)
if (!TextUtils.isEmpty(secondaryLabel)) {
Text(
secondaryLabel ?: "",
color = colors.secondaryLabel,
- modifier = Modifier.basicMarquee(),
+ modifier = Modifier.tileMarquee(),
)
}
}
}
}
+private fun Modifier.tileMarquee(): Modifier {
+ return basicMarquee(
+ iterations = 1,
+ initialDelayMillis = 200,
+ )
+}
+
@Composable
fun TileLazyGrid(
modifier: Modifier = Modifier,
@@ -270,6 +273,7 @@ fun DefaultEditTileGrid(
modifier: Modifier,
onAddTile: (TileSpec, Int) -> Unit,
onRemoveTile: (TileSpec) -> Unit,
+ onResize: (TileSpec, Boolean) -> Unit,
) {
val currentListState = rememberEditListState(tiles)
val dragAndDropState = rememberDragAndDropState(currentListState)
@@ -289,6 +293,9 @@ fun DefaultEditTileGrid(
val onDropRemove: (TileSpec, Int) -> Unit by rememberUpdatedState { tileSpec, _ ->
onRemoveTile(tileSpec)
}
+ val onDoubleTap: (TileSpec) -> Unit by rememberUpdatedState { tileSpec ->
+ onResize(tileSpec, !isIconOnly(tileSpec))
+ }
TileLazyGrid(
modifier = modifier.dragAndDropTileList(dragAndDropState, { true }, onDropAdd),
@@ -301,6 +308,7 @@ fun DefaultEditTileGrid(
currentTiles,
ClickAction.REMOVE,
onRemoveTile,
+ onDoubleTap,
isIconOnly,
indicatePosition = true,
dragAndDropState = dragAndDropState,
@@ -314,6 +322,7 @@ fun DefaultEditTileGrid(
otherTilesStock,
ClickAction.ADD,
addTileToEnd,
+ onDoubleTap,
isIconOnly,
dragAndDropState = dragAndDropState,
acceptDrops = { true },
@@ -328,6 +337,7 @@ fun DefaultEditTileGrid(
otherTilesCustom,
ClickAction.ADD,
addTileToEnd,
+ onDoubleTap,
isIconOnly,
dragAndDropState = dragAndDropState,
acceptDrops = { true },
@@ -340,6 +350,7 @@ fun LazyGridScope.editTiles(
tiles: List<EditTileViewModel>,
clickAction: ClickAction,
onClick: (TileSpec) -> Unit,
+ onDoubleTap: (TileSpec) -> Unit,
isIconOnly: (TileSpec) -> Boolean,
dragAndDropState: DragAndDropState,
acceptDrops: (TileSpec) -> Boolean,
@@ -386,6 +397,7 @@ fun LazyGridScope.editTiles(
.dragAndDropTileSource(
viewModel.tileSpec,
onClick,
+ onDoubleTap,
dragAndDropState,
)
)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/IconTilesViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/IconTilesViewModel.kt
index 117c85c9c3ba..8d2d74af5835 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/IconTilesViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/IconTilesViewModel.kt
@@ -23,10 +23,14 @@ import javax.inject.Inject
interface IconTilesViewModel {
fun isIconTile(spec: TileSpec): Boolean
+
+ fun resize(spec: TileSpec, toIcon: Boolean)
}
@SysUISingleton
class IconTilesViewModelImpl @Inject constructor(private val interactor: IconTilesInteractor) :
IconTilesViewModel {
override fun isIconTile(spec: TileSpec): Boolean = interactor.isIconTile(spec)
+
+ override fun resize(spec: TileSpec, toIcon: Boolean) = interactor.resize(spec, toIcon)
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/QuickQuickSettingsViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/QuickQuickSettingsViewModel.kt
index b3acaced8ef2..bb004946a4d1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/QuickQuickSettingsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/QuickQuickSettingsViewModel.kt
@@ -26,8 +26,8 @@ import com.android.systemui.qs.pipeline.shared.TileSpec
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.mapLatest
@@ -54,14 +54,24 @@ constructor(
quickQuickSettingsRowInteractor.defaultRows
)
- val tileViewModels: Flow<List<SizedTile<TileViewModel>>> =
- columns.flatMapLatest { columns ->
- tilesInteractor.currentTiles.combine(rows, ::Pair).mapLatest { (tiles, rows) ->
- tiles
- .map { SizedTile(TileViewModel(it.tile, it.spec), it.spec.width) }
- .let { splitInRowsSequence(it, columns).take(rows).toList().flatten() }
+ val tileViewModels: StateFlow<List<SizedTile<TileViewModel>>> =
+ columns
+ .flatMapLatest { columns ->
+ tilesInteractor.currentTiles.combine(rows, ::Pair).mapLatest { (tiles, rows) ->
+ tiles
+ .map { SizedTile(TileViewModel(it.tile, it.spec), it.spec.width) }
+ .let { splitInRowsSequence(it, columns).take(rows).toList().flatten() }
+ }
}
- }
+ .stateIn(
+ applicationScope,
+ SharingStarted.WhileSubscribed(),
+ tilesInteractor.currentTiles.value
+ .map { SizedTile(TileViewModel(it.tile, it.spec), it.spec.width) }
+ .let {
+ splitInRowsSequence(it, columns.value).take(rows.value).toList().flatten()
+ }
+ )
private val TileSpec.width: Int
get() = if (iconTilesViewModel.isIconTile(this)) 1 else 2
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/TileUiState.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/TileUiState.kt
index 578a292deb7c..4ec59c969a59 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/TileUiState.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/TileUiState.kt
@@ -16,20 +16,22 @@
package com.android.systemui.qs.panels.ui.viewmodel
+import androidx.compose.runtime.Immutable
import com.android.systemui.plugins.qs.QSTile
import java.util.function.Supplier
+@Immutable
data class TileUiState(
- val label: CharSequence,
- val secondaryLabel: CharSequence,
+ val label: String,
+ val secondaryLabel: String,
val state: Int,
val icon: Supplier<QSTile.Icon>,
)
fun QSTile.State.toUiState(): TileUiState {
return TileUiState(
- label ?: "",
- secondaryLabel ?: "",
+ label?.toString() ?: "",
+ secondaryLabel?.toString() ?: "",
state,
icon?.let { Supplier { icon } } ?: iconSupplier,
)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/TileViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/TileViewModel.kt
index 7505b90ee844..8578bb0ef9a1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/TileViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/TileViewModel.kt
@@ -16,6 +16,7 @@
package com.android.systemui.qs.panels.ui.viewmodel
+import androidx.compose.runtime.Immutable
import com.android.systemui.animation.Expandable
import com.android.systemui.plugins.qs.QSTile
import com.android.systemui.qs.pipeline.shared.TileSpec
@@ -25,6 +26,7 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.onStart
+@Immutable
class TileViewModel(private val tile: QSTile, val spec: TileSpec) {
val state: Flow<QSTile.State> =
conflatedCallbackFlow {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/ReduceBrightColorsAutoAddable.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/ReduceBrightColorsAutoAddable.kt
index 9c1b85799648..4d823ab216f0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/ReduceBrightColorsAutoAddable.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/ReduceBrightColorsAutoAddable.kt
@@ -38,10 +38,11 @@ class ReduceBrightColorsAutoAddable
@Inject
constructor(
controller: ReduceBrightColorsController,
- @Named(RBC_AVAILABLE) private val available: Boolean,
+ @Named(RBC_AVAILABLE) private var available: Boolean,
) :
CallbackControllerAutoAddable<
- ReduceBrightColorsController.Listener, ReduceBrightColorsController
+ ReduceBrightColorsController.Listener,
+ ReduceBrightColorsController
>(controller) {
override val spec: TileSpec
@@ -50,10 +51,16 @@ constructor(
override fun ProducerScope<AutoAddSignal>.getCallback(): ReduceBrightColorsController.Listener {
return object : ReduceBrightColorsController.Listener {
override fun onActivated(activated: Boolean) {
- if (activated) {
+ if (activated && available) {
sendAdd()
}
}
+
+ override fun onFeatureEnabledChanged(enabled: Boolean) {
+ if (!enabled) {
+ available = false
+ }
+ }
}
}
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 44c846b5c631..6b3dfe1b90ad 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
@@ -93,6 +93,7 @@ constructor(
@VisibleForTesting internal const val TILE_STATE_RES_PREFIX = "tile_states_"
@VisibleForTesting internal const val LONG_PRESS_EFFECT_WIDTH_SCALE = 1.1f
@VisibleForTesting internal const val LONG_PRESS_EFFECT_HEIGHT_SCALE = 1.2f
+ internal val EMPTY_RECT = Rect()
}
private val icon: QSIconViewImpl = QSIconViewImpl(context)
@@ -386,6 +387,7 @@ constructor(
// The launch animation of a long-press effect did not reset the long-press effect so
// we must do it here
resetLongPressEffectProperties()
+ longPressEffect.resetState()
}
val actualHeight =
if (heightOverride != HeightOverrideable.NO_OVERRIDE) {
@@ -771,11 +773,14 @@ constructor(
lastIconTint = icon.getColor(state)
// Long-press effects
+ longPressEffect?.qsTile?.state?.handlesLongClick = state.handlesLongClick
if (
state.handlesLongClick &&
longPressEffect?.initializeEffect(longPressEffectDuration) == true
) {
showRippleEffect = false
+ longPressEffect.qsTile?.state?.state = lastState // Store the tile's state
+ longPressEffect.resetState()
initializeLongPressProperties(measuredHeight, measuredWidth)
} else {
// Long-press effects might have been enabled before but the new state does not
@@ -906,12 +911,13 @@ constructor(
}
override fun onActivityLaunchAnimationEnd() {
+ longPressEffect?.resetState()
if (longPressEffect != null && !haveLongPressPropertiesBeenReset) {
resetLongPressEffectProperties()
}
}
- fun prepareForLaunch() {
+ private fun prepareForLaunch() {
val startingHeight = initialLongPressProperties?.height?.toInt() ?: 0
val startingWidth = initialLongPressProperties?.width?.toInt() ?: 0
val deltaH = finalLongPressProperties?.height?.minus(startingHeight)?.toInt() ?: 0
@@ -922,7 +928,12 @@ constructor(
paddingForLaunch.bottom = deltaH / 2
}
- override fun getPaddingForLaunchAnimation(): Rect = paddingForLaunch
+ override fun getPaddingForLaunchAnimation(): Rect =
+ if (longPressEffect?.state == QSLongPressEffect.State.LONG_CLICKED) {
+ paddingForLaunch
+ } else {
+ EMPTY_RECT
+ }
fun updateLongPressEffectProperties(effectProgress: Float) {
if (!isLongClickable || longPressEffect == null) return
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/SubtitleArrayMapping.kt b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/SubtitleArrayMapping.kt
index f34389ec8cb5..53594bbb2c84 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/SubtitleArrayMapping.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/SubtitleArrayMapping.kt
@@ -20,12 +20,14 @@ import com.android.systemui.res.R
/** Return the subtitle resource Id of the given tile. */
object SubtitleArrayMapping {
private val subtitleIdsMap: HashMap<String, Int> = HashMap()
+
init {
subtitleIdsMap["internet"] = R.array.tile_states_internet
subtitleIdsMap["wifi"] = R.array.tile_states_wifi
subtitleIdsMap["cell"] = R.array.tile_states_cell
subtitleIdsMap["battery"] = R.array.tile_states_battery
subtitleIdsMap["dnd"] = R.array.tile_states_dnd
+ subtitleIdsMap["modes"] = R.array.tile_states_modes
subtitleIdsMap["flashlight"] = R.array.tile_states_flashlight
subtitleIdsMap["rotation"] = R.array.tile_states_rotation
subtitleIdsMap["bt"] = R.array.tile_states_bt
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java
index 34723523b84f..af5b31180159 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java
@@ -48,12 +48,13 @@ import javax.inject.Named;
/** Quick settings tile: Reduce Bright Colors **/
public class ReduceBrightColorsTile extends QSTileImpl<QSTile.BooleanState>
- implements ReduceBrightColorsController.Listener{
+ implements ReduceBrightColorsController.Listener {
public static final String TILE_SPEC = "reduce_brightness";
- private final boolean mIsAvailable;
+ private boolean mIsAvailable;
private final ReduceBrightColorsController mReduceBrightColorsController;
private boolean mIsListening;
+ private final boolean mInUpgradeMode;
@Inject
public ReduceBrightColorsTile(
@@ -73,9 +74,11 @@ public class ReduceBrightColorsTile extends QSTileImpl<QSTile.BooleanState>
statusBarStateController, activityStarter, qsLogger);
mReduceBrightColorsController = reduceBrightColorsController;
mReduceBrightColorsController.observe(getLifecycle(), this);
- mIsAvailable = isAvailable;
+ mInUpgradeMode = reduceBrightColorsController.isInUpgradeMode(mContext.getResources());
+ mIsAvailable = isAvailable || mInUpgradeMode;
}
+
@Override
public boolean isAvailable() {
return mIsAvailable;
@@ -93,12 +96,28 @@ public class ReduceBrightColorsTile extends QSTileImpl<QSTile.BooleanState>
@Override
public Intent getLongClickIntent() {
- return new Intent(Settings.ACTION_REDUCE_BRIGHT_COLORS_SETTINGS);
+ return goToEvenDimmer() ? new Intent(Settings.ACTION_DISPLAY_SETTINGS) : new Intent(
+ Settings.ACTION_REDUCE_BRIGHT_COLORS_SETTINGS);
+ }
+
+ private boolean goToEvenDimmer() {
+ if (mInUpgradeMode) {
+ mHost.removeTile(getTileSpec());
+ mIsAvailable = false;
+ return true;
+ }
+ return false;
}
@Override
protected void handleClick(@Nullable Expandable expandable) {
- mReduceBrightColorsController.setReduceBrightColorsActivated(!mState.value);
+
+ if (goToEvenDimmer()) {
+ mActivityStarter.postStartActivityDismissingKeyguard(
+ new Intent(Settings.ACTION_DISPLAY_SETTINGS), 0);
+ } else {
+ mReduceBrightColorsController.setReduceBrightColorsActivated(!mState.value);
+ }
}
@Override
@@ -127,4 +146,9 @@ public class ReduceBrightColorsTile extends QSTileImpl<QSTile.BooleanState>
public void onActivated(boolean activated) {
refreshState();
}
+
+ @Override
+ public void onFeatureEnabledChanged(boolean enabled) {
+ refreshState();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegate.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegate.java
index c971f547c302..edc49cac2f92 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegate.java
@@ -183,9 +183,9 @@ public class InternetDialogDelegate implements
Context context,
InternetDialogManager internetDialogManager,
InternetDialogController internetDialogController,
- @Assisted(ABOVE_STATUS_BAR) boolean canConfigMobileData,
- @Assisted(CAN_CONFIG_MOBILE_DATA) boolean canConfigWifi,
- @Assisted(CAN_CONFIG_WIFI) boolean aboveStatusBar,
+ @Assisted(CAN_CONFIG_MOBILE_DATA) boolean canConfigMobileData,
+ @Assisted(CAN_CONFIG_WIFI) boolean canConfigWifi,
+ @Assisted(ABOVE_STATUS_BAR) boolean aboveStatusBar,
@Assisted CoroutineScope coroutineScope,
UiEventLogger uiEventLogger,
DialogTransitionAnimator dialogTransitionAnimator,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractor.kt
new file mode 100644
index 000000000000..da4d2f1c0085
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractor.kt
@@ -0,0 +1,46 @@
+/*
+ * 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.modes.domain.interactor
+
+import android.app.Flags
+import android.os.UserHandle
+import android.provider.Settings.Global.ZEN_MODE_OFF
+import com.android.settingslib.notification.data.repository.ZenModeRepository
+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.modes.domain.model.ModesTileModel
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.map
+
+class ModesTileDataInteractor @Inject constructor(val zenModeRepository: ZenModeRepository) :
+ QSTileDataInteractor<ModesTileModel> {
+ // TODO(b/346519570): This should be checking for any enabled modes.
+ private val zenModeActive =
+ zenModeRepository.globalZenMode.map { it != ZEN_MODE_OFF }.distinctUntilChanged()
+
+ override fun tileData(
+ user: UserHandle,
+ triggers: Flow<DataUpdateTrigger>
+ ): Flow<ModesTileModel> {
+ return zenModeActive.map { ModesTileModel(isActivated = it) }
+ }
+
+ override fun availability(user: UserHandle): Flow<Boolean> = flowOf(Flags.modesUi())
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileUserActionInteractor.kt
new file mode 100644
index 000000000000..e2fea84eced4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileUserActionInteractor.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.qs.tiles.impl.modes.domain.interactor
+
+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.modes.domain.model.ModesTileModel
+import com.android.systemui.qs.tiles.viewmodel.QSTileUserAction
+import javax.inject.Inject
+
+class ModesTileUserActionInteractor @Inject constructor() :
+ QSTileUserActionInteractor<ModesTileModel> {
+ override suspend fun handleInput(input: QSTileInput<ModesTileModel>) {
+ with(input) {
+ when (action) {
+ is QSTileUserAction.Click -> {
+ // TODO(b/346519570) open dialog
+ }
+ is QSTileUserAction.LongClick -> {
+ // TODO(b/346519570) open settings
+ }
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/model/ModesTileModel.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/model/ModesTileModel.kt
new file mode 100644
index 000000000000..e44413a962f4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/model/ModesTileModel.kt
@@ -0,0 +1,18 @@
+/*
+ * 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.modes.domain.model
+data class ModesTileModel(val isActivated: Boolean)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/ui/ModesTileMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/ui/ModesTileMapper.kt
new file mode 100644
index 000000000000..07b393e549c2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/ui/ModesTileMapper.kt
@@ -0,0 +1,59 @@
+/*
+ * 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.modes.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.modes.domain.model.ModesTileModel
+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
+
+class ModesTileMapper
+@Inject
+constructor(
+ @Main private val resources: Resources,
+ val theme: Resources.Theme,
+) : QSTileDataToStateMapper<ModesTileModel> {
+ override fun map(config: QSTileConfig, data: ModesTileModel): QSTileState =
+ QSTileState.build(resources, theme, config.uiConfig) {
+ val iconRes =
+ if (data.isActivated) {
+ R.drawable.qs_dnd_icon_on
+ } else {
+ R.drawable.qs_dnd_icon_off
+ }
+ val icon = Icon.Loaded(resources.getDrawable(iconRes, theme), contentDescription = null)
+ this.icon = { icon }
+ if (data.isActivated) {
+ activationState = QSTileState.ActivationState.ACTIVE
+ secondaryLabel = "Some modes enabled idk" // TODO(b/346519570)
+ } else {
+ activationState = QSTileState.ActivationState.INACTIVE
+ secondaryLabel = "Off" // TODO(b/346519570)
+ }
+ contentDescription = label
+ supportedActions =
+ setOf(
+ QSTileState.UserAction.CLICK,
+ QSTileState.UserAction.LONG_CLICK,
+ )
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/reducebrightness/domain/interactor/ReduceBrightColorsTileDataInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/reducebrightness/domain/interactor/ReduceBrightColorsTileDataInteractor.kt
index 98fd561b27d6..00b1e41461f5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/reducebrightness/domain/interactor/ReduceBrightColorsTileDataInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/reducebrightness/domain/interactor/ReduceBrightColorsTileDataInteractor.kt
@@ -23,13 +23,13 @@ import com.android.systemui.qs.dagger.QSFlagsModule.RBC_AVAILABLE
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.reducebrightness.domain.model.ReduceBrightColorsTileModel
+import com.android.systemui.util.kotlin.isAvailable
import com.android.systemui.util.kotlin.isEnabled
import javax.inject.Inject
import javax.inject.Named
import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.distinctUntilChanged
-import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
@@ -52,5 +52,7 @@ constructor(
.map { ReduceBrightColorsTileModel(it) }
.flowOn(bgCoroutineContext)
}
- override fun availability(user: UserHandle): Flow<Boolean> = flowOf(isAvailable)
+
+ override fun availability(user: UserHandle): Flow<Boolean> =
+ reduceBrightColorsController.isAvailable()
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/reducebrightness/domain/interactor/ReduceBrightColorsTileUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/reducebrightness/domain/interactor/ReduceBrightColorsTileUserActionInteractor.kt
index 14dbe0e8a69a..ed5e4fe74962 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/reducebrightness/domain/interactor/ReduceBrightColorsTileUserActionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/reducebrightness/domain/interactor/ReduceBrightColorsTileUserActionInteractor.kt
@@ -17,7 +17,9 @@
package com.android.systemui.qs.tiles.impl.reducebrightness.domain.interactor
import android.content.Intent
+import android.content.res.Resources
import android.provider.Settings
+import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.qs.ReduceBrightColorsController
import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandler
import com.android.systemui.qs.tiles.base.interactor.QSTileInput
@@ -30,19 +32,40 @@ import javax.inject.Inject
class ReduceBrightColorsTileUserActionInteractor
@Inject
constructor(
+ @Main private val resources: Resources,
private val qsTileIntentUserActionHandler: QSTileIntentUserInputHandler,
private val reduceBrightColorsController: ReduceBrightColorsController,
) : QSTileUserActionInteractor<ReduceBrightColorsTileModel> {
+ val isInUpgradeMode: Boolean = reduceBrightColorsController.isInUpgradeMode(resources)
+
override suspend fun handleInput(input: QSTileInput<ReduceBrightColorsTileModel>): Unit =
with(input) {
when (action) {
is QSTileUserAction.Click -> {
+ if (isInUpgradeMode) {
+ reduceBrightColorsController.setReduceBrightColorsFeatureAvailable(false)
+ qsTileIntentUserActionHandler.handle(
+ action.expandable,
+ Intent(Settings.ACTION_DISPLAY_SETTINGS)
+ )
+ // TODO(b/349458355): show dialog
+ return@with
+ }
reduceBrightColorsController.setReduceBrightColorsActivated(
!input.data.isEnabled
)
}
is QSTileUserAction.LongClick -> {
+ if (isInUpgradeMode) {
+ reduceBrightColorsController.setReduceBrightColorsFeatureAvailable(false)
+ qsTileIntentUserActionHandler.handle(
+ action.expandable,
+ Intent(Settings.ACTION_DISPLAY_SETTINGS)
+ )
+ // TODO(b/349458355): show dialog
+ return@with
+ }
qsTileIntentUserActionHandler.handle(
action.expandable,
Intent(Settings.ACTION_REDUCE_BRIGHT_COLORS_SETTINGS)
diff --git a/packages/SystemUI/src/com/android/systemui/recordissue/RecordIssueDialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/recordissue/RecordIssueDialogDelegate.kt
index bbf4e51b35e9..8a51ad4cbd71 100644
--- a/packages/SystemUI/src/com/android/systemui/recordissue/RecordIssueDialogDelegate.kt
+++ b/packages/SystemUI/src/com/android/systemui/recordissue/RecordIssueDialogDelegate.kt
@@ -87,7 +87,10 @@ constructor(
setNegativeButton(R.string.cancel) { _, _ -> }
setPositiveButton(R.string.qs_record_issue_start) { _, _ -> onStarted.run() }
}
- bgExecutor.execute { traceurMessageSender.bindToTraceur(dialog.context) }
+ bgExecutor.execute {
+ traceurMessageSender.onBoundToTraceur.add { traceurMessageSender.getTags() }
+ traceurMessageSender.bindToTraceur(dialog.context)
+ }
}
override fun createDialog(): SystemUIDialog = factory.create(this)
diff --git a/packages/SystemUI/src/com/android/systemui/recordissue/TraceurMessageSender.kt b/packages/SystemUI/src/com/android/systemui/recordissue/TraceurMessageSender.kt
index 903d662c69ff..a31a9ef26b16 100644
--- a/packages/SystemUI/src/com/android/systemui/recordissue/TraceurMessageSender.kt
+++ b/packages/SystemUI/src/com/android/systemui/recordissue/TraceurMessageSender.kt
@@ -45,11 +45,15 @@ class TraceurMessageSender @Inject constructor(@Background private val backgroun
private var binder: Messenger? = null
private var isBound: Boolean = false
+ val onBoundToTraceur = mutableListOf<Runnable>()
+
private val traceurConnection =
object : ServiceConnection {
override fun onServiceConnected(className: ComponentName, service: IBinder) {
binder = Messenger(service)
isBound = true
+ onBoundToTraceur.forEach(Runnable::run)
+ onBoundToTraceur.clear()
}
override fun onServiceDisconnected(className: ComponentName) {
@@ -103,11 +107,17 @@ class TraceurMessageSender @Inject constructor(@Background private val backgroun
@WorkerThread
fun shareTraces(context: Context, screenRecord: Uri?) {
- val replyHandler = Messenger(TraceurMessageHandler(context, screenRecord, backgroundLooper))
+ val replyHandler = Messenger(ShareFilesHandler(context, screenRecord, backgroundLooper))
notifyTraceur(MessageConstants.SHARE_WHAT, replyTo = replyHandler)
}
@WorkerThread
+ fun getTags() {
+ val replyHandler = Messenger(TagsHandler(backgroundLooper))
+ notifyTraceur(MessageConstants.TAGS_WHAT, replyTo = replyHandler)
+ }
+
+ @WorkerThread
private fun notifyTraceur(what: Int, data: Bundle = Bundle(), replyTo: Messenger? = null) {
try {
binder!!.send(
@@ -122,7 +132,7 @@ class TraceurMessageSender @Inject constructor(@Background private val backgroun
}
}
- private class TraceurMessageHandler(
+ private class ShareFilesHandler(
private val context: Context,
private val screenRecord: Uri?,
looper: Looper,
@@ -154,4 +164,29 @@ class TraceurMessageSender @Inject constructor(@Background private val backgroun
context.startActivity(fileSharingIntent)
}
}
+
+ private class TagsHandler(looper: Looper) : Handler(looper) {
+
+ override fun handleMessage(msg: Message) {
+ if (MessageConstants.TAGS_WHAT == msg.what) {
+ val keys = msg.data.getStringArrayList(MessageConstants.BUNDLE_KEY_TAGS)
+ val values =
+ msg.data.getStringArrayList(MessageConstants.BUNDLE_KEY_TAG_DESCRIPTIONS)
+ if (keys == null || values == null) {
+ throw IllegalArgumentException(
+ "Neither keys: $keys, nor values: $values can " + "be null"
+ )
+ }
+
+ val tags = keys.zip(values).map { "${it.first}: ${it.second}" }.toSet()
+ Log.e(
+ TAG,
+ "These tags: $tags will be saved and used for the Custom Trace" +
+ " Config dialog in a future CL. This log will be removed."
+ )
+ } else {
+ throw IllegalArgumentException("received unknown msg.what: " + msg.what)
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ActionExecutor.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ActionExecutor.kt
index 1868b4a29f20..54e0319da58f 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ActionExecutor.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ActionExecutor.kt
@@ -40,7 +40,7 @@ constructor(
private val intentExecutor: ActionIntentExecutor,
@Application private val applicationScope: CoroutineScope,
@Assisted val window: Window,
- @Assisted val viewProxy: ScreenshotViewProxy,
+ @Assisted val viewProxy: ScreenshotShelfViewProxy,
@Assisted val finishDismiss: () -> Unit,
) {
@@ -109,7 +109,7 @@ constructor(
interface Factory {
fun create(
window: Window,
- viewProxy: ScreenshotViewProxy,
+ viewProxy: ScreenshotShelfViewProxy,
finishDismiss: (() -> Unit)
): ActionExecutor
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/LegacyScreenshotViewProxy.kt b/packages/SystemUI/src/com/android/systemui/screenshot/LegacyScreenshotViewProxy.kt
deleted file mode 100644
index 3d024a6a8ccf..000000000000
--- a/packages/SystemUI/src/com/android/systemui/screenshot/LegacyScreenshotViewProxy.kt
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.screenshot
-
-import android.animation.Animator
-import android.app.Notification
-import android.content.Context
-import android.graphics.Bitmap
-import android.graphics.Rect
-import android.util.Log
-import android.view.KeyEvent
-import android.view.LayoutInflater
-import android.view.ScrollCaptureResponse
-import android.view.View
-import android.view.ViewTreeObserver
-import android.view.WindowInsets
-import android.window.OnBackInvokedCallback
-import android.window.OnBackInvokedDispatcher
-import androidx.appcompat.content.res.AppCompatResources
-import com.android.internal.logging.UiEventLogger
-import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.res.R
-import com.android.systemui.screenshot.LogConfig.DEBUG_DISMISS
-import com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_DISMISSED_OTHER
-import com.android.systemui.screenshot.scroll.ScrollCaptureController
-import dagger.assisted.Assisted
-import dagger.assisted.AssistedFactory
-import dagger.assisted.AssistedInject
-
-/**
- * Legacy implementation of screenshot view methods. Just proxies the calls down into the original
- * ScreenshotView.
- */
-class LegacyScreenshotViewProxy
-@AssistedInject
-constructor(
- private val logger: UiEventLogger,
- flags: FeatureFlags,
- @Assisted private val context: Context,
- @Assisted private val displayId: Int
-) : ScreenshotViewProxy {
- override val view: ScreenshotView =
- LayoutInflater.from(context).inflate(R.layout.screenshot, null) as ScreenshotView
- override val screenshotPreview: View
- override var packageName: String = ""
- set(value) {
- field = value
- view.setPackageName(value)
- }
- override var callbacks: ScreenshotView.ScreenshotViewCallback? = null
- set(value) {
- field = value
- view.setCallbacks(value)
- }
- override var screenshot: ScreenshotData? = null
- set(value) {
- field = value
- value?.let {
- val badgeBg =
- AppCompatResources.getDrawable(context, R.drawable.overlay_badge_background)
- val user = it.userHandle
- if (badgeBg != null && user != null) {
- view.badgeScreenshot(context.packageManager.getUserBadgedIcon(badgeBg, user))
- }
- view.setScreenshot(it)
- }
- }
-
- override val isAttachedToWindow
- get() = view.isAttachedToWindow
- override val isDismissing
- get() = view.isDismissing
- override val isPendingSharedTransition
- get() = view.isPendingSharedTransition
-
- init {
- view.setUiEventLogger(logger)
- view.setDefaultDisplay(displayId)
- view.setFlags(flags)
- addPredictiveBackListener { requestDismissal(SCREENSHOT_DISMISSED_OTHER) }
- setOnKeyListener { requestDismissal(SCREENSHOT_DISMISSED_OTHER) }
- if (LogConfig.DEBUG_WINDOW) {
- Log.d(TAG, "adding OnComputeInternalInsetsListener")
- }
- view.viewTreeObserver.addOnComputeInternalInsetsListener(view)
- screenshotPreview = view.screenshotPreview
- }
-
- override fun reset() = view.reset()
- override fun updateInsets(insets: WindowInsets) = view.updateInsets(insets)
- override fun updateOrientation(insets: WindowInsets) = view.updateOrientation(insets)
-
- override fun createScreenshotDropInAnimation(screenRect: Rect, showFlash: Boolean): Animator =
- view.createScreenshotDropInAnimation(screenRect, showFlash)
-
- override fun addQuickShareChip(quickShareAction: Notification.Action) =
- view.addQuickShareChip(quickShareAction)
-
- override fun setChipIntents(imageData: ScreenshotController.SavedImageData) =
- view.setChipIntents(imageData)
-
- override fun requestDismissal(event: ScreenshotEvent?) {
- if (DEBUG_DISMISS) {
- Log.d(TAG, "screenshot dismissal requested")
- }
- // If we're already animating out, don't restart the animation
- if (view.isDismissing) {
- if (DEBUG_DISMISS) {
- Log.v(TAG, "Already dismissing, ignoring duplicate command $event")
- }
- return
- }
- event?.let { logger.log(event, 0, packageName) }
- view.animateDismissal()
- }
-
- override fun showScrollChip(packageName: String, onClick: Runnable) =
- view.showScrollChip(packageName, onClick)
-
- override fun hideScrollChip() = view.hideScrollChip()
-
- override fun prepareScrollingTransition(
- response: ScrollCaptureResponse,
- screenBitmap: Bitmap,
- newScreenshot: Bitmap,
- screenshotTakenInPortrait: Boolean,
- onTransitionPrepared: Runnable,
- ) {
- view.prepareScrollingTransition(
- response,
- screenBitmap,
- newScreenshot,
- screenshotTakenInPortrait
- )
- view.post { onTransitionPrepared.run() }
- }
-
- override fun startLongScreenshotTransition(
- transitionDestination: Rect,
- onTransitionEnd: Runnable,
- longScreenshot: ScrollCaptureController.LongScreenshot
- ) = view.startLongScreenshotTransition(transitionDestination, onTransitionEnd, longScreenshot)
-
- override fun restoreNonScrollingUi() = view.restoreNonScrollingUi()
-
- override fun fadeForSharedTransition() {} // unused
-
- override fun stopInputListening() = view.stopInputListening()
-
- override fun requestFocus() {
- view.requestFocus()
- }
-
- override fun announceForAccessibility(string: String) = view.announceForAccessibility(string)
-
- override fun prepareEntranceAnimation(runnable: Runnable) {
- view.viewTreeObserver.addOnPreDrawListener(
- object : ViewTreeObserver.OnPreDrawListener {
- override fun onPreDraw(): Boolean {
- if (LogConfig.DEBUG_WINDOW) {
- Log.d(TAG, "onPreDraw: startAnimation")
- }
- view.viewTreeObserver.removeOnPreDrawListener(this)
- runnable.run()
- return true
- }
- }
- )
- }
-
- private fun addPredictiveBackListener(onDismissRequested: (ScreenshotEvent) -> Unit) {
- val onBackInvokedCallback = OnBackInvokedCallback {
- if (LogConfig.DEBUG_INPUT) {
- Log.d(TAG, "Predictive Back callback dispatched")
- }
- onDismissRequested.invoke(SCREENSHOT_DISMISSED_OTHER)
- }
- view.addOnAttachStateChangeListener(
- object : View.OnAttachStateChangeListener {
- override fun onViewAttachedToWindow(v: View) {
- if (LogConfig.DEBUG_INPUT) {
- Log.d(TAG, "Registering Predictive Back callback")
- }
- view
- .findOnBackInvokedDispatcher()
- ?.registerOnBackInvokedCallback(
- OnBackInvokedDispatcher.PRIORITY_DEFAULT,
- onBackInvokedCallback
- )
- }
-
- override fun onViewDetachedFromWindow(view: View) {
- if (LogConfig.DEBUG_INPUT) {
- Log.d(TAG, "Unregistering Predictive Back callback")
- }
- view
- .findOnBackInvokedDispatcher()
- ?.unregisterOnBackInvokedCallback(onBackInvokedCallback)
- }
- }
- )
- }
- private fun setOnKeyListener(onDismissRequested: (ScreenshotEvent) -> Unit) {
- view.setOnKeyListener(
- object : View.OnKeyListener {
- override fun onKey(view: View, keyCode: Int, event: KeyEvent): Boolean {
- if (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_ESCAPE) {
- if (LogConfig.DEBUG_INPUT) {
- Log.d(TAG, "onKeyEvent: $keyCode")
- }
- onDismissRequested.invoke(SCREENSHOT_DISMISSED_OTHER)
- return true
- }
- return false
- }
- }
- )
- }
-
- @AssistedFactory
- interface Factory : ScreenshotViewProxy.Factory {
- override fun getProxy(context: Context, displayId: Int): LegacyScreenshotViewProxy
- }
-
- companion object {
- private const val TAG = "LegacyScreenshotViewProxy"
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/MessageContainerController.kt b/packages/SystemUI/src/com/android/systemui/screenshot/MessageContainerController.kt
index 596046268984..474afa8bcb9d 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/MessageContainerController.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/MessageContainerController.kt
@@ -137,7 +137,7 @@ constructor(
val offset = container.height + params.topMargin + params.bottomMargin
val anim = if (animateIn) ValueAnimator.ofFloat(0f, 1f) else ValueAnimator.ofFloat(1f, 0f)
with(anim) {
- duration = ScreenshotView.SCREENSHOT_ACTIONS_EXPANSION_DURATION_MS
+ duration = MESSAGE_EXPANSION_DURATION_MS
interpolator = AccelerateDecelerateInterpolator()
addUpdateListener { valueAnimator: ValueAnimator ->
val interpolation = valueAnimator.animatedValue as Float
@@ -147,4 +147,8 @@ constructor(
}
return anim
}
+
+ companion object {
+ const val MESSAGE_EXPANSION_DURATION_MS: Long = 400
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
index c87b1f526957..773900981759 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
@@ -20,7 +20,7 @@ import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.view.WindowManager.LayoutParams.TYPE_SCREENSHOT;
import static com.android.systemui.Flags.screenshotPrivateProfileAccessibilityAnnouncementFix;
-import static com.android.systemui.Flags.screenshotShelfUi2;
+import static com.android.systemui.Flags.screenshotSaveImageExporter;
import static com.android.systemui.screenshot.LogConfig.DEBUG_ANIM;
import static com.android.systemui.screenshot.LogConfig.DEBUG_CALLBACK;
import static com.android.systemui.screenshot.LogConfig.DEBUG_INPUT;
@@ -191,7 +191,7 @@ public class ScreenshotController implements ScreenshotHandler {
private final WindowContext mContext;
private final FeatureFlags mFlags;
- private final ScreenshotViewProxy mViewProxy;
+ private final ScreenshotShelfViewProxy mViewProxy;
private final ScreenshotNotificationsController mNotificationsController;
private final ScreenshotSmartActions mScreenshotSmartActions;
private final UiEventLogger mUiEventLogger;
@@ -231,13 +231,6 @@ public class ScreenshotController implements ScreenshotHandler {
private String mPackageName = "";
private final BroadcastReceiver mCopyBroadcastReceiver;
- // When false, the screenshot is taken without showing the ui. Note that this only applies to
- // external displays, as on the default one the UI should **always** be shown.
- // This is needed in case of screenshot during display mirroring, as adding another window to
- // the external display makes mirroring stop.
- // When there is a way to distinguish between displays that are mirroring or extending, this
- // can be removed and we can directly show the ui only in the extended case.
- private final Boolean mShowUIOnExternalDisplay;
/** Tracks config changes that require re-creating UI */
private final InterestingConfigChanges mConfigChanges = new InterestingConfigChanges(
ActivityInfo.CONFIG_ORIENTATION
@@ -253,7 +246,7 @@ public class ScreenshotController implements ScreenshotHandler {
Context context,
WindowManager windowManager,
FeatureFlags flags,
- ScreenshotViewProxy.Factory viewProxyFactory,
+ ScreenshotShelfViewProxy.Factory viewProxyFactory,
ScreenshotSmartActions screenshotSmartActions,
ScreenshotNotificationsController.Factory screenshotNotificationsControllerFactory,
UiEventLogger uiEventLogger,
@@ -273,8 +266,7 @@ public class ScreenshotController implements ScreenshotHandler {
MessageContainerController messageContainerController,
Provider<ScreenshotSoundController> screenshotSoundController,
AnnouncementResolver announcementResolver,
- @Assisted Display display,
- @Assisted boolean showUIOnExternalDisplay
+ @Assisted Display display
) {
mScreenshotSmartActions = screenshotSmartActions;
mNotificationsController = screenshotNotificationsControllerFactory.create(
@@ -348,7 +340,6 @@ public class ScreenshotController implements ScreenshotHandler {
mBroadcastDispatcher.registerReceiver(mCopyBroadcastReceiver, new IntentFilter(
ClipboardOverlayController.COPY_OVERLAY_ACTION), null, null,
Context.RECEIVER_NOT_EXPORTED, ClipboardOverlayController.SELF_PERMISSION);
- mShowUIOnExternalDisplay = showUIOnExternalDisplay;
}
@Override
@@ -382,7 +373,7 @@ public class ScreenshotController implements ScreenshotHandler {
Log.w(TAG, "User setup not complete, displaying toast only");
// User setup isn't complete, so we don't want to show any UI beyond a toast, as editing
// and sharing shouldn't be exposed to the user.
- saveScreenshotAndToast(screenshot.getUserHandle(), finisher);
+ saveScreenshotAndToast(screenshot, finisher);
return;
}
@@ -398,31 +389,23 @@ public class ScreenshotController implements ScreenshotHandler {
prepareViewForNewScreenshot(screenshot, oldPackageName);
- if (!shouldShowUi()) {
- saveScreenshotInWorkerThread(
- screenshot.getUserHandle(), finisher, this::logSuccessOnActionsReady,
- (ignored) -> {
- });
- return;
- }
-
final UUID requestId;
- if (screenshotShelfUi2()) {
- requestId = mActionsController.setCurrentScreenshot(screenshot);
- saveScreenshotInBackground(screenshot, requestId, finisher);
-
- if (screenshot.getTaskId() >= 0) {
- mAssistContentRequester.requestAssistContent(
- screenshot.getTaskId(),
- assistContent ->
- mActionsController.onAssistContent(requestId, assistContent));
- } else {
- mActionsController.onAssistContent(requestId, null);
+ requestId = mActionsController.setCurrentScreenshot(screenshot);
+ saveScreenshotInBackground(screenshot, requestId, finisher, result -> {
+ if (result.uri != null) {
+ ScreenshotSavedResult savedScreenshot = new ScreenshotSavedResult(
+ result.uri, screenshot.getUserOrDefault(), result.timestamp);
+ mActionsController.setCompletedScreenshot(requestId, savedScreenshot);
}
+ });
+
+ if (screenshot.getTaskId() >= 0) {
+ mAssistContentRequester.requestAssistContent(
+ screenshot.getTaskId(),
+ assistContent ->
+ mActionsController.onAssistContent(requestId, assistContent));
} else {
- requestId = UUID.randomUUID(); // passed through but unused for legacy UI
- saveScreenshotInWorkerThread(screenshot.getUserHandle(), finisher,
- this::showUiOnActionsReady, this::showUiOnQuickShareActionReady);
+ mActionsController.onAssistContent(requestId, null);
}
// The window is focusable by default
@@ -458,13 +441,6 @@ public class ScreenshotController implements ScreenshotHandler {
// ignore system bar insets for the purpose of window layout
mWindow.getDecorView().setOnApplyWindowInsetsListener(
(v, insets) -> WindowInsets.CONSUMED);
- if (!screenshotShelfUi2()) {
- mScreenshotHandler.cancelTimeout(); // restarted after animation
- }
- }
-
- private boolean shouldShowUi() {
- return mDisplay.getDisplayId() == Display.DEFAULT_DISPLAY || mShowUIOnExternalDisplay;
}
void prepareViewForNewScreenshot(@NonNull ScreenshotData screenshot, String oldPackageName) {
@@ -501,9 +477,6 @@ public class ScreenshotController implements ScreenshotHandler {
}
mViewProxy.setPackageName(mPackageName);
-
- mViewProxy.updateOrientation(
- mWindowManager.getCurrentWindowMetrics().getWindowInsets());
}
/**
@@ -515,11 +488,7 @@ public class ScreenshotController implements ScreenshotHandler {
}
boolean isPendingSharedTransition() {
- if (screenshotShelfUi2()) {
- return mActionExecutor.isPendingSharedTransition();
- } else {
- return mViewProxy.isPendingSharedTransition();
- }
+ return mActionExecutor.isPendingSharedTransition();
}
// Any cleanup needed when the service is being destroyed.
@@ -556,7 +525,7 @@ public class ScreenshotController implements ScreenshotHandler {
}
mMessageContainerController.setView(mViewProxy.getView());
- mViewProxy.setCallbacks(new ScreenshotView.ScreenshotViewCallback() {
+ mViewProxy.setCallbacks(new ScreenshotShelfViewProxy.ScreenshotViewCallback() {
@Override
public void onUserInteraction() {
if (DEBUG_INPUT) {
@@ -566,13 +535,6 @@ public class ScreenshotController implements ScreenshotHandler {
}
@Override
- public void onAction(Intent intent, UserHandle owner, boolean overrideTransition) {
- Pair<ActivityOptions, ExitTransitionCoordinator> exit = createWindowTransition();
- mActionIntentExecutor.launchIntentAsync(
- intent, owner, overrideTransition, exit.first, exit.second);
- }
-
- @Override
public void onDismiss() {
finishDismiss();
}
@@ -603,11 +565,7 @@ public class ScreenshotController implements ScreenshotHandler {
if (mConfigChanges.applyNewConfig(mContext.getResources())) {
// Hide the scroll chip until we know it's available in this
// orientation
- if (screenshotShelfUi2()) {
- mActionsController.onScrollChipInvalidated();
- } else {
- mViewProxy.hideScrollChip();
- }
+ mActionsController.onScrollChipInvalidated();
// Delay scroll capture eval a bit to allow the underlying activity
// to set up in the new orientation.
mScreenshotHandler.postDelayed(
@@ -640,13 +598,8 @@ public class ScreenshotController implements ScreenshotHandler {
(response) -> {
mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_LONG_SCREENSHOT_IMPRESSION,
0, response.getPackageName());
- if (screenshotShelfUi2()) {
- mActionsController.onScrollChipReady(requestId,
- () -> onScrollButtonClicked(owner, response));
- } else {
- mViewProxy.showScrollChip(response.getPackageName(),
- () -> onScrollButtonClicked(owner, response));
- }
+ mActionsController.onScrollChipReady(requestId,
+ () -> onScrollButtonClicked(owner, response));
return Unit.INSTANCE;
}
);
@@ -715,11 +668,9 @@ public class ScreenshotController implements ScreenshotHandler {
mWindowManager.addView(decorView, mWindowLayoutParams);
decorView.requestApplyInsets();
- if (screenshotShelfUi2()) {
- ViewGroup layout = decorView.requireViewById(android.R.id.content);
- layout.setClipChildren(false);
- layout.setClipToPadding(false);
- }
+ ViewGroup layout = decorView.requireViewById(android.R.id.content);
+ layout.setClipChildren(false);
+ layout.setClipToPadding(false);
}
void removeWindow() {
@@ -749,29 +700,40 @@ public class ScreenshotController implements ScreenshotHandler {
* Save the bitmap but don't show the normal screenshot UI.. just a toast (or notification on
* failure).
*/
- private void saveScreenshotAndToast(UserHandle owner, Consumer<Uri> finisher) {
+ private void saveScreenshotAndToast(ScreenshotData screenshot, Consumer<Uri> finisher) {
// Play the shutter sound to notify that we've taken a screenshot
playCameraSoundIfNeeded();
- saveScreenshotInWorkerThread(
- owner,
- /* onComplete */ finisher,
- /* actionsReadyListener */ imageData -> {
- if (DEBUG_CALLBACK) {
- Log.d(TAG, "returning URI to finisher (Consumer<URI>): " + imageData.uri);
- }
- finisher.accept(imageData.uri);
- if (imageData.uri == null) {
- mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_NOT_SAVED, 0, mPackageName);
- mNotificationsController.notifyScreenshotError(
- R.string.screenshot_failed_to_save_text);
- } else {
- mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_SAVED, 0, mPackageName);
- mScreenshotHandler.post(() -> Toast.makeText(mContext,
- R.string.screenshot_saved_title, Toast.LENGTH_SHORT).show());
- }
- },
- null);
+ if (screenshotSaveImageExporter()) {
+ saveScreenshotInBackground(screenshot, UUID.randomUUID(), finisher, result -> {
+ if (result.uri != null) {
+ mScreenshotHandler.post(() -> Toast.makeText(mContext,
+ R.string.screenshot_saved_title, Toast.LENGTH_SHORT).show());
+ }
+ });
+ } else {
+ saveScreenshotInWorkerThread(
+ screenshot.getUserHandle(),
+ /* onComplete */ finisher,
+ /* actionsReadyListener */ imageData -> {
+ if (DEBUG_CALLBACK) {
+ Log.d(TAG,
+ "returning URI to finisher (Consumer<URI>): " + imageData.uri);
+ }
+ finisher.accept(imageData.uri);
+ if (imageData.uri == null) {
+ mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_NOT_SAVED, 0,
+ mPackageName);
+ mNotificationsController.notifyScreenshotError(
+ R.string.screenshot_failed_to_save_text);
+ } else {
+ mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_SAVED, 0, mPackageName);
+ mScreenshotHandler.post(() -> Toast.makeText(mContext,
+ R.string.screenshot_saved_title, Toast.LENGTH_SHORT).show());
+ }
+ },
+ null);
+ }
}
/**
@@ -844,8 +806,8 @@ public class ScreenshotController implements ScreenshotHandler {
mScreenshotHandler.cancelTimeout();
}
- private void saveScreenshotInBackground(
- ScreenshotData screenshot, UUID requestId, Consumer<Uri> finisher) {
+ private void saveScreenshotInBackground(ScreenshotData screenshot, UUID requestId,
+ Consumer<Uri> finisher, Consumer<ImageExporter.Result> onResult) {
ListenableFuture<ImageExporter.Result> future = mImageExporter.export(mBgExecutor,
requestId, screenshot.getBitmap(), screenshot.getUserOrDefault(),
mDisplay.getDisplayId());
@@ -854,10 +816,7 @@ public class ScreenshotController implements ScreenshotHandler {
ImageExporter.Result result = future.get();
Log.d(TAG, "Saved screenshot: " + result);
logScreenshotResultStatus(result.uri, screenshot.getUserHandle());
- if (result.uri != null) {
- mActionsController.setCompletedScreenshot(requestId, new ScreenshotSavedResult(
- result.uri, screenshot.getUserOrDefault(), result.timestamp));
- }
+ onResult.accept(result);
if (DEBUG_CALLBACK) {
Log.d(TAG, "finished background processing, Calling (Consumer<Uri>) "
+ "finisher.accept(\"" + result.uri + "\"");
@@ -902,62 +861,6 @@ public class ScreenshotController implements ScreenshotHandler {
mSaveInBgTask.execute();
}
-
- /**
- * Sets up the action shade and its entrance animation, once we get the screenshot URI.
- */
- private void showUiOnActionsReady(ScreenshotController.SavedImageData imageData) {
- logSuccessOnActionsReady(imageData);
- mScreenshotHandler.resetTimeout();
-
- if (imageData.uri != null) {
- if (DEBUG_UI) {
- Log.d(TAG, "Showing UI actions");
- }
- if (!imageData.owner.equals(Process.myUserHandle())) {
- Log.d(TAG, "Screenshot saved to user " + imageData.owner + " as "
- + imageData.uri);
- }
- mScreenshotHandler.post(() -> {
- if (mScreenshotAnimation != null && mScreenshotAnimation.isRunning()) {
- mScreenshotAnimation.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- super.onAnimationEnd(animation);
- mViewProxy.setChipIntents(imageData);
- }
- });
- } else {
- mViewProxy.setChipIntents(imageData);
- }
- });
- }
- }
-
- /**
- * Sets up the action shade and its entrance animation, once we get the Quick Share action data.
- */
- private void showUiOnQuickShareActionReady(ScreenshotController.QuickShareData quickShareData) {
- if (DEBUG_UI) {
- Log.d(TAG, "Showing UI for Quick Share action");
- }
- if (quickShareData.quickShareAction != null) {
- mScreenshotHandler.post(() -> {
- if (mScreenshotAnimation != null && mScreenshotAnimation.isRunning()) {
- mScreenshotAnimation.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- super.onAnimationEnd(animation);
- mViewProxy.addQuickShareChip(quickShareData.quickShareAction);
- }
- });
- } else {
- mViewProxy.addQuickShareChip(quickShareData.quickShareAction);
- }
- });
- }
- }
-
/**
* Logs success/failure of the screenshot saving task, and shows an error if it failed.
*/
@@ -1053,9 +956,7 @@ public class ScreenshotController implements ScreenshotHandler {
* Creates an instance of the controller for that specific display.
*
* @param display display to capture
- * @param showUIOnExternalDisplay Whether the UI should be shown if this is an external
- * display.
*/
- ScreenshotController create(Display display, boolean showUIOnExternalDisplay);
+ ScreenshotController create(Display display);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotShelfViewProxy.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotShelfViewProxy.kt
index 1b5fa345ebb4..50215af30ad4 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotShelfViewProxy.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotShelfViewProxy.kt
@@ -18,7 +18,6 @@ package com.android.systemui.screenshot
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
-import android.app.Notification
import android.content.Context
import android.graphics.Bitmap
import android.graphics.Rect
@@ -45,7 +44,6 @@ import com.android.systemui.res.R
import com.android.systemui.screenshot.LogConfig.DEBUG_DISMISS
import com.android.systemui.screenshot.LogConfig.DEBUG_INPUT
import com.android.systemui.screenshot.LogConfig.DEBUG_WINDOW
-import com.android.systemui.screenshot.ScreenshotController.SavedImageData
import com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_DISMISSED_OTHER
import com.android.systemui.screenshot.scroll.ScrollCaptureController
import com.android.systemui.screenshot.ui.ScreenshotAnimationController
@@ -70,13 +68,23 @@ constructor(
private val thumbnailObserver: ThumbnailObserver,
@Assisted private val context: Context,
@Assisted private val displayId: Int
-) : ScreenshotViewProxy {
- override val view: ScreenshotShelfView =
+) {
+
+ interface ScreenshotViewCallback {
+ fun onUserInteraction()
+
+ fun onDismiss()
+
+ /** DOWN motion event was observed outside of the touchable areas of this view. */
+ fun onTouchOutside()
+ }
+
+ val view: ScreenshotShelfView =
LayoutInflater.from(context).inflate(R.layout.screenshot_shelf, null) as ScreenshotShelfView
- override val screenshotPreview: View
- override var packageName: String = ""
- override var callbacks: ScreenshotView.ScreenshotViewCallback? = null
- override var screenshot: ScreenshotData? = null
+ val screenshotPreview: View
+ var packageName: String = ""
+ var callbacks: ScreenshotViewCallback? = null
+ var screenshot: ScreenshotData? = null
set(value) {
value?.let {
viewModel.setScreenshotBitmap(it.bitmap)
@@ -92,10 +100,11 @@ constructor(
field = value
}
- override val isAttachedToWindow
+ val isAttachedToWindow
get() = view.isAttachedToWindow
- override var isDismissing = false
- override var isPendingSharedTransition = false
+
+ var isDismissing = false
+ var isPendingSharedTransition = false
private val animationController = ScreenshotAnimationController(view, viewModel)
private var inputMonitor: InputMonitorCompat? = null
@@ -136,17 +145,17 @@ constructor(
)
}
- override fun reset() {
+ fun reset() {
animationController.cancel()
isPendingSharedTransition = false
viewModel.reset()
}
- override fun updateInsets(insets: WindowInsets) {
+
+ fun updateInsets(insets: WindowInsets) {
view.updateInsets(insets)
}
- override fun updateOrientation(insets: WindowInsets) {}
- override fun createScreenshotDropInAnimation(screenRect: Rect, showFlash: Boolean): Animator {
+ fun createScreenshotDropInAnimation(screenRect: Rect, showFlash: Boolean): Animator {
val entrance =
animationController.getEntranceAnimation(screenRect, showFlash) {
viewModel.setAnimationState(AnimationState.ENTRANCE_REVEAL)
@@ -164,11 +173,7 @@ constructor(
return entrance
}
- override fun addQuickShareChip(quickShareAction: Notification.Action) {}
-
- override fun setChipIntents(imageData: SavedImageData) {}
-
- override fun requestDismissal(event: ScreenshotEvent?) {
+ fun requestDismissal(event: ScreenshotEvent?) {
requestDismissal(event, null)
}
@@ -187,6 +192,7 @@ constructor(
override fun onAnimationStart(animator: Animator) {
isDismissing = true
}
+
override fun onAnimationEnd(animator: Animator) {
isDismissing = false
callbacks?.onDismiss()
@@ -196,11 +202,7 @@ constructor(
animator.start()
}
- override fun showScrollChip(packageName: String, onClick: Runnable) {}
-
- override fun hideScrollChip() {}
-
- override fun prepareScrollingTransition(
+ fun prepareScrollingTransition(
response: ScrollCaptureResponse,
screenBitmap: Bitmap, // unused
newScreenshot: Bitmap,
@@ -228,7 +230,7 @@ constructor(
return r
}
- override fun startLongScreenshotTransition(
+ fun startLongScreenshotTransition(
transitionDestination: Rect,
onTransitionEnd: Runnable,
longScreenshot: ScrollCaptureController.LongScreenshot,
@@ -243,27 +245,27 @@ constructor(
transitionAnimation.start()
}
- override fun restoreNonScrollingUi() {
+ fun restoreNonScrollingUi() {
viewModel.setScrollableRect(null)
viewModel.setScrollingScrimBitmap(null)
animationController.restoreUI()
callbacks?.onUserInteraction() // reset the timeout
}
- override fun stopInputListening() {
+ fun stopInputListening() {
inputMonitor?.dispose()
inputMonitor = null
inputEventReceiver?.dispose()
inputEventReceiver = null
}
- override fun requestFocus() {
+ fun requestFocus() {
view.requestFocus()
}
- override fun announceForAccessibility(string: String) = view.announceForAccessibility(string)
+ fun announceForAccessibility(string: String) = view.announceForAccessibility(string)
- override fun prepareEntranceAnimation(runnable: Runnable) {
+ fun prepareEntranceAnimation(runnable: Runnable) {
view.viewTreeObserver.addOnPreDrawListener(
object : ViewTreeObserver.OnPreDrawListener {
override fun onPreDraw(): Boolean {
@@ -276,7 +278,7 @@ constructor(
)
}
- override fun fadeForSharedTransition() {
+ fun fadeForSharedTransition() {
animationController.fadeForSharedTransition()
}
@@ -349,7 +351,7 @@ constructor(
}
@AssistedFactory
- interface Factory : ScreenshotViewProxy.Factory {
- override fun getProxy(context: Context, displayId: Int): ScreenshotShelfViewProxy
+ interface Factory {
+ fun getProxy(context: Context, displayId: Int): ScreenshotShelfViewProxy
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
deleted file mode 100644
index 59e38a836258..000000000000
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
+++ /dev/null
@@ -1,1126 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.screenshot;
-
-import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
-
-import static com.android.internal.jank.InteractionJankMonitor.CUJ_TAKE_SCREENSHOT;
-import static com.android.systemui.screenshot.LogConfig.DEBUG_ANIM;
-import static com.android.systemui.screenshot.LogConfig.DEBUG_DISMISS;
-import static com.android.systemui.screenshot.LogConfig.DEBUG_INPUT;
-import static com.android.systemui.screenshot.LogConfig.DEBUG_SCROLL;
-import static com.android.systemui.screenshot.LogConfig.DEBUG_UI;
-import static com.android.systemui.screenshot.LogConfig.DEBUG_WINDOW;
-import static com.android.systemui.screenshot.LogConfig.logTag;
-import static com.android.systemui.screenshot.ScreenshotController.SCREENSHOT_CORNER_DEFAULT_TIMEOUT_MILLIS;
-
-import static java.util.Objects.requireNonNull;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
-import android.animation.ValueAnimator;
-import android.annotation.Nullable;
-import android.app.ActivityManager;
-import android.app.BroadcastOptions;
-import android.app.Notification;
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.ColorStateList;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.BlendMode;
-import android.graphics.Color;
-import android.graphics.Insets;
-import android.graphics.Matrix;
-import android.graphics.PointF;
-import android.graphics.Rect;
-import android.graphics.Region;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.Icon;
-import android.graphics.drawable.InsetDrawable;
-import android.graphics.drawable.LayerDrawable;
-import android.os.Bundle;
-import android.os.Looper;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.util.AttributeSet;
-import android.util.DisplayMetrics;
-import android.util.Log;
-import android.util.MathUtils;
-import android.view.Choreographer;
-import android.view.Display;
-import android.view.DisplayCutout;
-import android.view.GestureDetector;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.ScrollCaptureResponse;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewTreeObserver;
-import android.view.WindowInsets;
-import android.view.WindowManager;
-import android.view.WindowMetrics;
-import android.view.accessibility.AccessibilityManager;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
-import android.widget.FrameLayout;
-import android.widget.HorizontalScrollView;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-
-import androidx.constraintlayout.widget.ConstraintLayout;
-
-import com.android.internal.jank.InteractionJankMonitor;
-import com.android.internal.logging.UiEventLogger;
-import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.res.R;
-import com.android.systemui.screenshot.scroll.ScrollCaptureController;
-import com.android.systemui.shared.system.InputChannelCompat;
-import com.android.systemui.shared.system.InputMonitorCompat;
-import com.android.systemui.shared.system.QuickStepContract;
-
-import java.util.ArrayList;
-
-/**
- * Handles the visual elements and animations for the screenshot flow.
- */
-public class ScreenshotView extends FrameLayout implements
- ViewTreeObserver.OnComputeInternalInsetsListener {
-
- public interface ScreenshotViewCallback {
- void onUserInteraction();
-
- void onAction(Intent intent, UserHandle owner, boolean overrideTransition);
-
- void onDismiss();
-
- /** DOWN motion event was observed outside of the touchable areas of this view. */
- void onTouchOutside();
- }
-
- private static final String TAG = logTag(ScreenshotView.class);
-
- private static final long SCREENSHOT_FLASH_IN_DURATION_MS = 133;
- private static final long SCREENSHOT_FLASH_OUT_DURATION_MS = 217;
- // delay before starting to fade in dismiss button
- private static final long SCREENSHOT_TO_CORNER_DISMISS_DELAY_MS = 200;
- private static final long SCREENSHOT_TO_CORNER_X_DURATION_MS = 234;
- private static final long SCREENSHOT_TO_CORNER_Y_DURATION_MS = 500;
- private static final long SCREENSHOT_TO_CORNER_SCALE_DURATION_MS = 234;
- public static final long SCREENSHOT_ACTIONS_EXPANSION_DURATION_MS = 400;
- private static final long SCREENSHOT_ACTIONS_ALPHA_DURATION_MS = 100;
- private static final float SCREENSHOT_ACTIONS_START_SCALE_X = .7f;
-
- private final Resources mResources;
- private final Interpolator mFastOutSlowIn;
- private final DisplayMetrics mDisplayMetrics;
- private final float mFixedSize;
- private final AccessibilityManager mAccessibilityManager;
- private final GestureDetector mSwipeDetector;
-
- private int mDefaultDisplay = Display.DEFAULT_DISPLAY;
- private int mNavMode;
- private boolean mOrientationPortrait;
- private boolean mDirectionLTR;
-
- private ImageView mScrollingScrim;
- private DraggableConstraintLayout mScreenshotStatic;
- private ImageView mScreenshotPreview;
- private ImageView mScreenshotBadge;
- private View mScreenshotPreviewBorder;
- private ImageView mScrollablePreview;
- private ImageView mScreenshotFlash;
- private ImageView mActionsContainerBackground;
- private HorizontalScrollView mActionsContainer;
- private LinearLayout mActionsView;
- private FrameLayout mDismissButton;
- private OverlayActionChip mShareChip;
- private OverlayActionChip mEditChip;
- private OverlayActionChip mScrollChip;
- private OverlayActionChip mQuickShareChip;
-
- private UiEventLogger mUiEventLogger;
- private ScreenshotViewCallback mCallbacks;
- private boolean mPendingSharedTransition;
- private InputMonitorCompat mInputMonitor;
- private InputChannelCompat.InputEventReceiver mInputEventReceiver;
- private boolean mShowScrollablePreview;
- private String mPackageName = "";
-
- private final ArrayList<OverlayActionChip> mSmartChips = new ArrayList<>();
- private PendingInteraction mPendingInteraction;
- // Should only be set/used if the SCREENSHOT_METADATA flag is set.
- private ScreenshotData mScreenshotData;
-
- private final InteractionJankMonitor mInteractionJankMonitor;
- private FeatureFlags mFlags;
- private final Bundle mInteractiveBroadcastOption;
-
- private enum PendingInteraction {
- PREVIEW,
- EDIT,
- SHARE,
- QUICK_SHARE
- }
-
- public ScreenshotView(Context context) {
- this(context, null);
- }
-
- public ScreenshotView(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public ScreenshotView(Context context, AttributeSet attrs, int defStyleAttr) {
- this(context, attrs, defStyleAttr, 0);
- }
-
- public ScreenshotView(
- Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
- super(context, attrs, defStyleAttr, defStyleRes);
- mResources = mContext.getResources();
- mInteractionJankMonitor = getInteractionJankMonitorInstance();
-
- BroadcastOptions options = BroadcastOptions.makeBasic();
- options.setInteractive(true);
- mInteractiveBroadcastOption = options.toBundle();
-
- mFixedSize = mResources.getDimensionPixelSize(R.dimen.overlay_x_scale);
-
- // standard material ease
- mFastOutSlowIn =
- AnimationUtils.loadInterpolator(mContext, android.R.interpolator.fast_out_slow_in);
-
- mDisplayMetrics = new DisplayMetrics();
- mContext.getDisplay().getRealMetrics(mDisplayMetrics);
-
- mAccessibilityManager = AccessibilityManager.getInstance(mContext);
-
- mSwipeDetector = new GestureDetector(mContext,
- new GestureDetector.SimpleOnGestureListener() {
- final Rect mActionsRect = new Rect();
-
- @Override
- public boolean onScroll(
- MotionEvent ev1, MotionEvent ev2, float distanceX, float distanceY) {
- mActionsContainer.getBoundsOnScreen(mActionsRect);
- // return true if we aren't in the actions bar, or if we are but it isn't
- // scrollable in the direction of movement
- return !mActionsRect.contains((int) ev2.getRawX(), (int) ev2.getRawY())
- || !mActionsContainer.canScrollHorizontally((int) distanceX);
- }
- });
- mSwipeDetector.setIsLongpressEnabled(false);
- addOnAttachStateChangeListener(new OnAttachStateChangeListener() {
- @Override
- public void onViewAttachedToWindow(View v) {
- startInputListening();
- }
-
- @Override
- public void onViewDetachedFromWindow(View v) {
- stopInputListening();
- }
- });
- }
-
- private InteractionJankMonitor getInteractionJankMonitorInstance() {
- return InteractionJankMonitor.getInstance();
- }
-
- public void hideScrollChip() {
- mScrollChip.setVisibility(View.GONE);
- }
-
- /**
- * Called to display the scroll action chip when support is detected.
- *
- * @param packageName the owning package of the window to be captured
- * @param onClick the action to take when the chip is clicked.
- */
- public void showScrollChip(String packageName, Runnable onClick) {
- if (DEBUG_SCROLL) {
- Log.d(TAG, "Showing Scroll option");
- }
- mScrollChip.setVisibility(VISIBLE);
- mScrollChip.setOnClickListener((v) -> onClick.run());
- }
-
- @Override // ViewTreeObserver.OnComputeInternalInsetsListener
- public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo inoutInfo) {
- inoutInfo.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
- inoutInfo.touchableRegion.set(getTouchRegion(true));
- }
-
- private Region getSwipeRegion() {
- Region swipeRegion = new Region();
-
- final Rect tmpRect = new Rect();
- int swipePadding = (int) FloatingWindowUtil.dpToPx(
- mDisplayMetrics, DraggableConstraintLayout.SWIPE_PADDING_DP * -1);
- mScreenshotPreview.getBoundsOnScreen(tmpRect);
- tmpRect.inset(swipePadding, swipePadding);
- swipeRegion.op(tmpRect, Region.Op.UNION);
- mActionsContainerBackground.getBoundsOnScreen(tmpRect);
- tmpRect.inset(swipePadding, swipePadding);
- swipeRegion.op(tmpRect, Region.Op.UNION);
- mDismissButton.getBoundsOnScreen(tmpRect);
- swipeRegion.op(tmpRect, Region.Op.UNION);
-
- View messageContainer = findViewById(R.id.screenshot_message_container);
- if (messageContainer != null) {
- messageContainer.getBoundsOnScreen(tmpRect);
- swipeRegion.op(tmpRect, Region.Op.UNION);
- }
- View messageDismiss = findViewById(R.id.message_dismiss_button);
- if (messageDismiss != null) {
- messageDismiss.getBoundsOnScreen(tmpRect);
- swipeRegion.op(tmpRect, Region.Op.UNION);
- }
-
- return swipeRegion;
- }
-
- private Region getTouchRegion(boolean includeScrim) {
- Region touchRegion = getSwipeRegion();
-
- if (includeScrim && mScrollingScrim.getVisibility() == View.VISIBLE) {
- final Rect tmpRect = new Rect();
- mScrollingScrim.getBoundsOnScreen(tmpRect);
- touchRegion.op(tmpRect, Region.Op.UNION);
- }
-
- if (QuickStepContract.isGesturalMode(mNavMode)) {
- final WindowManager wm = mContext.getSystemService(WindowManager.class);
- final WindowMetrics windowMetrics = wm.getCurrentWindowMetrics();
- final Insets gestureInsets = windowMetrics.getWindowInsets().getInsets(
- WindowInsets.Type.systemGestures());
- // Receive touches in gesture insets such that they don't cause TOUCH_OUTSIDE
- Rect inset = new Rect(0, 0, gestureInsets.left, mDisplayMetrics.heightPixels);
- touchRegion.op(inset, Region.Op.UNION);
- inset.set(mDisplayMetrics.widthPixels - gestureInsets.right, 0,
- mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels);
- touchRegion.op(inset, Region.Op.UNION);
- }
- return touchRegion;
- }
-
- private void startInputListening() {
- stopInputListening();
- mInputMonitor = new InputMonitorCompat("Screenshot", mDefaultDisplay);
- mInputEventReceiver = mInputMonitor.getInputReceiver(
- Looper.getMainLooper(), Choreographer.getInstance(), ev -> {
- if (ev instanceof MotionEvent) {
- MotionEvent event = (MotionEvent) ev;
- if (event.getActionMasked() == MotionEvent.ACTION_DOWN
- && !getTouchRegion(false).contains(
- (int) event.getRawX(), (int) event.getRawY())) {
- mCallbacks.onTouchOutside();
- }
- }
- });
- }
-
- void stopInputListening() {
- if (mInputMonitor != null) {
- mInputMonitor.dispose();
- mInputMonitor = null;
- }
- if (mInputEventReceiver != null) {
- mInputEventReceiver.dispose();
- mInputEventReceiver = null;
- }
- }
-
- @Override // View
- protected void onFinishInflate() {
- super.onFinishInflate();
- mScrollingScrim = requireNonNull(findViewById(R.id.screenshot_scrolling_scrim));
- mScreenshotStatic = requireNonNull(findViewById(R.id.screenshot_static));
- mScreenshotPreview = requireNonNull(findViewById(R.id.screenshot_preview));
-
- mScreenshotPreviewBorder = requireNonNull(
- findViewById(R.id.screenshot_preview_border));
- mScreenshotPreview.setClipToOutline(true);
- mScreenshotBadge = requireNonNull(findViewById(R.id.screenshot_badge));
-
- mActionsContainerBackground = requireNonNull(findViewById(
- R.id.actions_container_background));
- mActionsContainer = requireNonNull(findViewById(R.id.actions_container));
- mActionsView = requireNonNull(findViewById(R.id.screenshot_actions));
- mDismissButton = requireNonNull(findViewById(R.id.screenshot_dismiss_button));
- mScrollablePreview = requireNonNull(findViewById(R.id.screenshot_scrollable_preview));
- mScreenshotFlash = requireNonNull(findViewById(R.id.screenshot_flash));
- mShareChip = requireNonNull(mActionsContainer.findViewById(R.id.screenshot_share_chip));
- mEditChip = requireNonNull(mActionsContainer.findViewById(R.id.screenshot_edit_chip));
- mScrollChip = requireNonNull(mActionsContainer.findViewById(R.id.screenshot_scroll_chip));
-
- setFocusable(true);
- mActionsContainer.setScrollX(0);
-
- mNavMode = getResources().getInteger(
- com.android.internal.R.integer.config_navBarInteractionMode);
- mOrientationPortrait =
- getResources().getConfiguration().orientation == ORIENTATION_PORTRAIT;
- mDirectionLTR =
- getResources().getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_LTR;
-
- // Get focus so that the key events go to the layout.
- setFocusableInTouchMode(true);
- requestFocus();
-
- mScreenshotStatic.setCallbacks(new DraggableConstraintLayout.SwipeDismissCallbacks() {
- @Override
- public void onInteraction() {
- mCallbacks.onUserInteraction();
- }
-
- @Override
- public void onSwipeDismissInitiated(Animator animator) {
- if (DEBUG_DISMISS) {
- Log.d(ScreenshotView.TAG, "dismiss triggered via swipe gesture");
- }
- mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_SWIPE_DISMISSED, 0,
- mPackageName);
- }
-
- @Override
- public void onDismissComplete() {
- if (mInteractionJankMonitor.isInstrumenting(CUJ_TAKE_SCREENSHOT)) {
- mInteractionJankMonitor.end(CUJ_TAKE_SCREENSHOT);
- }
- mCallbacks.onDismiss();
- }
- });
- }
-
- View getScreenshotPreview() {
- return mScreenshotPreview;
- }
-
- void setUiEventLogger(UiEventLogger uiEventLogger) {
- mUiEventLogger = uiEventLogger;
- }
-
- void setCallbacks(ScreenshotViewCallback callbacks) {
- mCallbacks = callbacks;
- }
-
- void setFlags(FeatureFlags flags) {
- mFlags = flags;
- }
-
- void setScreenshot(Bitmap bitmap, Insets screenInsets) {
- mScreenshotPreview.setImageDrawable(createScreenDrawable(mResources, bitmap, screenInsets));
- }
-
- void setScreenshot(ScreenshotData screenshot) {
- mScreenshotData = screenshot;
- setScreenshot(screenshot.getBitmap(), screenshot.getInsets());
- mScreenshotPreview.setImageDrawable(createScreenDrawable(mResources, screenshot.getBitmap(),
- screenshot.getInsets()));
- }
-
- void setPackageName(String packageName) {
- mPackageName = packageName;
- }
-
- void setDefaultDisplay(int displayId) {
- mDefaultDisplay = displayId;
- }
-
- void updateInsets(WindowInsets insets) {
- int orientation = mContext.getResources().getConfiguration().orientation;
- mOrientationPortrait = (orientation == ORIENTATION_PORTRAIT);
- FrameLayout.LayoutParams p =
- (FrameLayout.LayoutParams) mScreenshotStatic.getLayoutParams();
- DisplayCutout cutout = insets.getDisplayCutout();
- Insets navBarInsets = insets.getInsets(WindowInsets.Type.navigationBars());
- if (cutout == null) {
- p.setMargins(0, 0, 0, navBarInsets.bottom);
- } else {
- Insets waterfall = cutout.getWaterfallInsets();
- if (mOrientationPortrait) {
- p.setMargins(
- waterfall.left,
- Math.max(cutout.getSafeInsetTop(), waterfall.top),
- waterfall.right,
- Math.max(cutout.getSafeInsetBottom(),
- Math.max(navBarInsets.bottom, waterfall.bottom)));
- } else {
- p.setMargins(
- Math.max(cutout.getSafeInsetLeft(), waterfall.left),
- waterfall.top,
- Math.max(cutout.getSafeInsetRight(), waterfall.right),
- Math.max(navBarInsets.bottom, waterfall.bottom));
- }
- }
- mScreenshotStatic.setLayoutParams(p);
- mScreenshotStatic.requestLayout();
- }
-
- void updateOrientation(WindowInsets insets) {
- int orientation = mContext.getResources().getConfiguration().orientation;
- mOrientationPortrait = (orientation == ORIENTATION_PORTRAIT);
- updateInsets(insets);
- ViewGroup.LayoutParams params = mScreenshotPreview.getLayoutParams();
- if (mOrientationPortrait) {
- params.width = (int) mFixedSize;
- params.height = LayoutParams.WRAP_CONTENT;
- mScreenshotPreview.setScaleType(ImageView.ScaleType.FIT_START);
- } else {
- params.width = LayoutParams.WRAP_CONTENT;
- params.height = (int) mFixedSize;
- mScreenshotPreview.setScaleType(ImageView.ScaleType.FIT_END);
- }
-
- mScreenshotPreview.setLayoutParams(params);
- }
-
- AnimatorSet createScreenshotDropInAnimation(Rect bounds, boolean showFlash) {
- if (DEBUG_ANIM) {
- Log.d(TAG, "createAnim: bounds=" + bounds + " showFlash=" + showFlash);
- }
-
- Rect targetPosition = new Rect();
- mScreenshotPreview.getHitRect(targetPosition);
-
- // ratio of preview width, end vs. start size
- float cornerScale =
- mFixedSize / (mOrientationPortrait ? bounds.width() : bounds.height());
- final float currentScale = 1 / cornerScale;
-
- AnimatorSet dropInAnimation = new AnimatorSet();
- ValueAnimator flashInAnimator = ValueAnimator.ofFloat(0, 1);
- flashInAnimator.setDuration(SCREENSHOT_FLASH_IN_DURATION_MS);
- flashInAnimator.setInterpolator(mFastOutSlowIn);
- flashInAnimator.addUpdateListener(animation ->
- mScreenshotFlash.setAlpha((float) animation.getAnimatedValue()));
-
- ValueAnimator flashOutAnimator = ValueAnimator.ofFloat(1, 0);
- flashOutAnimator.setDuration(SCREENSHOT_FLASH_OUT_DURATION_MS);
- flashOutAnimator.setInterpolator(mFastOutSlowIn);
- flashOutAnimator.addUpdateListener(animation ->
- mScreenshotFlash.setAlpha((float) animation.getAnimatedValue()));
-
- // animate from the current location, to the static preview location
- final PointF startPos = new PointF(bounds.centerX(), bounds.centerY());
- final PointF finalPos = new PointF(targetPosition.exactCenterX(),
- targetPosition.exactCenterY());
-
- // Shift to screen coordinates so that the animation runs on top of the entire screen,
- // including e.g. bars covering the display cutout.
- int[] locInScreen = mScreenshotPreview.getLocationOnScreen();
- startPos.offset(targetPosition.left - locInScreen[0], targetPosition.top - locInScreen[1]);
-
- if (DEBUG_ANIM) {
- Log.d(TAG, "toCorner: startPos=" + startPos);
- Log.d(TAG, "toCorner: finalPos=" + finalPos);
- }
-
- ValueAnimator toCorner = ValueAnimator.ofFloat(0, 1);
- toCorner.setDuration(SCREENSHOT_TO_CORNER_Y_DURATION_MS);
-
- toCorner.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- mScreenshotPreview.setScaleX(currentScale);
- mScreenshotPreview.setScaleY(currentScale);
- mScreenshotPreview.setVisibility(View.VISIBLE);
- if (mAccessibilityManager.isEnabled()) {
- mDismissButton.setAlpha(0);
- mDismissButton.setVisibility(View.VISIBLE);
- }
- }
- });
-
- float xPositionPct =
- SCREENSHOT_TO_CORNER_X_DURATION_MS / (float) SCREENSHOT_TO_CORNER_Y_DURATION_MS;
- float dismissPct =
- SCREENSHOT_TO_CORNER_DISMISS_DELAY_MS / (float) SCREENSHOT_TO_CORNER_Y_DURATION_MS;
- float scalePct =
- SCREENSHOT_TO_CORNER_SCALE_DURATION_MS / (float) SCREENSHOT_TO_CORNER_Y_DURATION_MS;
- toCorner.addUpdateListener(animation -> {
- float t = animation.getAnimatedFraction();
- if (t < scalePct) {
- float scale = MathUtils.lerp(
- currentScale, 1, mFastOutSlowIn.getInterpolation(t / scalePct));
- mScreenshotPreview.setScaleX(scale);
- mScreenshotPreview.setScaleY(scale);
- } else {
- mScreenshotPreview.setScaleX(1);
- mScreenshotPreview.setScaleY(1);
- }
-
- if (t < xPositionPct) {
- float xCenter = MathUtils.lerp(startPos.x, finalPos.x,
- mFastOutSlowIn.getInterpolation(t / xPositionPct));
- mScreenshotPreview.setX(xCenter - mScreenshotPreview.getWidth() / 2f);
- } else {
- mScreenshotPreview.setX(finalPos.x - mScreenshotPreview.getWidth() / 2f);
- }
- float yCenter = MathUtils.lerp(
- startPos.y, finalPos.y, mFastOutSlowIn.getInterpolation(t));
- mScreenshotPreview.setY(yCenter - mScreenshotPreview.getHeight() / 2f);
-
- if (t >= dismissPct) {
- mDismissButton.setAlpha((t - dismissPct) / (1 - dismissPct));
- float currentX = mScreenshotPreview.getX();
- float currentY = mScreenshotPreview.getY();
- mDismissButton.setY(currentY - mDismissButton.getHeight() / 2f);
- if (mDirectionLTR) {
- mDismissButton.setX(currentX + mScreenshotPreview.getWidth()
- - mDismissButton.getWidth() / 2f);
- } else {
- mDismissButton.setX(currentX - mDismissButton.getWidth() / 2f);
- }
- }
- });
-
- mScreenshotFlash.setAlpha(0f);
- mScreenshotFlash.setVisibility(View.VISIBLE);
-
- ValueAnimator borderFadeIn = ValueAnimator.ofFloat(0, 1);
- borderFadeIn.setDuration(100);
- borderFadeIn.addUpdateListener((animation) -> {
- float borderAlpha = animation.getAnimatedFraction();
- mScreenshotPreviewBorder.setAlpha(borderAlpha);
- mScreenshotBadge.setAlpha(borderAlpha);
- });
-
- if (showFlash) {
- dropInAnimation.play(flashOutAnimator).after(flashInAnimator);
- dropInAnimation.play(flashOutAnimator).with(toCorner);
- } else {
- dropInAnimation.play(toCorner);
- }
- dropInAnimation.play(borderFadeIn).after(toCorner);
-
- dropInAnimation.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationCancel(Animator animation) {
- mInteractionJankMonitor.cancel(CUJ_TAKE_SCREENSHOT);
- }
-
- @Override
- public void onAnimationStart(Animator animation) {
- InteractionJankMonitor.Configuration.Builder builder =
- InteractionJankMonitor.Configuration.Builder.withView(
- CUJ_TAKE_SCREENSHOT, mScreenshotPreview)
- .setTag("DropIn");
- mInteractionJankMonitor.begin(builder);
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- if (DEBUG_ANIM) {
- Log.d(TAG, "drop-in animation ended");
- }
- mDismissButton.setOnClickListener(view -> {
- if (DEBUG_INPUT) {
- Log.d(TAG, "dismiss button clicked");
- }
- mUiEventLogger.log(
- ScreenshotEvent.SCREENSHOT_EXPLICIT_DISMISSAL, 0, mPackageName);
- animateDismissal();
- });
- mDismissButton.setAlpha(1);
- float dismissOffset = mDismissButton.getWidth() / 2f;
- float finalDismissX = mDirectionLTR
- ? finalPos.x - dismissOffset + bounds.width() * cornerScale / 2f
- : finalPos.x - dismissOffset - bounds.width() * cornerScale / 2f;
- mDismissButton.setX(finalDismissX);
- mDismissButton.setY(
- finalPos.y - dismissOffset - bounds.height() * cornerScale / 2f);
- mScreenshotPreview.setScaleX(1);
- mScreenshotPreview.setScaleY(1);
- mScreenshotPreview.setX(finalPos.x - mScreenshotPreview.getWidth() / 2f);
- mScreenshotPreview.setY(finalPos.y - mScreenshotPreview.getHeight() / 2f);
- requestLayout();
- mInteractionJankMonitor.end(CUJ_TAKE_SCREENSHOT);
- createScreenshotActionsShadeAnimation().start();
- }
- });
-
- return dropInAnimation;
- }
-
- ValueAnimator createScreenshotActionsShadeAnimation() {
- // By default the activities won't be able to start immediately; override this to keep
- // the same behavior as if started from a notification
- try {
- ActivityManager.getService().resumeAppSwitches();
- } catch (RemoteException e) {
- }
-
- ArrayList<OverlayActionChip> chips = new ArrayList<>();
-
- mShareChip.setContentDescription(mContext.getString(R.string.screenshot_share_description));
- mShareChip.setIcon(Icon.createWithResource(mContext, R.drawable.ic_screenshot_share), true);
- mShareChip.setOnClickListener(v -> {
- mShareChip.setIsPending(true);
- mEditChip.setIsPending(false);
- if (mQuickShareChip != null) {
- mQuickShareChip.setIsPending(false);
- }
- mPendingInteraction = PendingInteraction.SHARE;
- });
- chips.add(mShareChip);
-
- mEditChip.setContentDescription(
- mContext.getString(R.string.screenshot_edit_description));
- mEditChip.setIcon(Icon.createWithResource(mContext, R.drawable.ic_screenshot_edit),
- true);
- mEditChip.setOnClickListener(v -> {
- mEditChip.setIsPending(true);
- mShareChip.setIsPending(false);
- if (mQuickShareChip != null) {
- mQuickShareChip.setIsPending(false);
- }
- mPendingInteraction = PendingInteraction.EDIT;
- });
- chips.add(mEditChip);
-
- mScreenshotPreview.setOnClickListener(v -> {
- mShareChip.setIsPending(false);
- mEditChip.setIsPending(false);
- if (mQuickShareChip != null) {
- mQuickShareChip.setIsPending(false);
- }
- mPendingInteraction = PendingInteraction.PREVIEW;
- });
-
- mScrollChip.setText(mContext.getString(R.string.screenshot_scroll_label));
- mScrollChip.setIcon(Icon.createWithResource(mContext,
- R.drawable.ic_screenshot_scroll), true);
- chips.add(mScrollChip);
-
- // remove the margin from the last chip so that it's correctly aligned with the end
- LinearLayout.LayoutParams params = (LinearLayout.LayoutParams)
- mActionsView.getChildAt(0).getLayoutParams();
- params.setMarginEnd(0);
- mActionsView.getChildAt(0).setLayoutParams(params);
-
- ValueAnimator animator = ValueAnimator.ofFloat(0, 1);
- animator.setDuration(SCREENSHOT_ACTIONS_EXPANSION_DURATION_MS);
- float alphaFraction = (float) SCREENSHOT_ACTIONS_ALPHA_DURATION_MS
- / SCREENSHOT_ACTIONS_EXPANSION_DURATION_MS;
- mActionsContainer.setAlpha(0f);
- mActionsContainerBackground.setAlpha(0f);
- mActionsContainer.setVisibility(View.VISIBLE);
- mActionsContainerBackground.setVisibility(View.VISIBLE);
-
- animator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationCancel(Animator animation) {
- mInteractionJankMonitor.cancel(CUJ_TAKE_SCREENSHOT);
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- mInteractionJankMonitor.end(CUJ_TAKE_SCREENSHOT);
- }
-
- @Override
- public void onAnimationStart(Animator animation) {
- InteractionJankMonitor.Configuration.Builder builder =
- InteractionJankMonitor.Configuration.Builder.withView(
- CUJ_TAKE_SCREENSHOT, mScreenshotStatic)
- .setTag("Actions")
- .setTimeout(SCREENSHOT_CORNER_DEFAULT_TIMEOUT_MILLIS);
- mInteractionJankMonitor.begin(builder);
- }
- });
-
- animator.addUpdateListener(animation -> {
- float t = animation.getAnimatedFraction();
- float containerAlpha = t < alphaFraction ? t / alphaFraction : 1;
- mActionsContainer.setAlpha(containerAlpha);
- mActionsContainerBackground.setAlpha(containerAlpha);
- float containerScale = SCREENSHOT_ACTIONS_START_SCALE_X
- + (t * (1 - SCREENSHOT_ACTIONS_START_SCALE_X));
- mActionsContainer.setScaleX(containerScale);
- mActionsContainerBackground.setScaleX(containerScale);
- for (OverlayActionChip chip : chips) {
- chip.setAlpha(t);
- chip.setScaleX(1 / containerScale); // invert to keep size of children constant
- }
- mActionsContainer.setScrollX(mDirectionLTR ? 0 : mActionsContainer.getWidth());
- mActionsContainer.setPivotX(mDirectionLTR ? 0 : mActionsContainer.getWidth());
- mActionsContainerBackground.setPivotX(
- mDirectionLTR ? 0 : mActionsContainerBackground.getWidth());
- });
- return animator;
- }
-
- void badgeScreenshot(@Nullable Drawable badge) {
- mScreenshotBadge.setImageDrawable(badge);
- mScreenshotBadge.setVisibility(badge != null ? View.VISIBLE : View.GONE);
- }
-
- void setChipIntents(ScreenshotController.SavedImageData imageData) {
- mShareChip.setOnClickListener(v -> {
- mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_SHARE_TAPPED, 0, mPackageName);
- prepareSharedTransition();
-
- Intent shareIntent = ActionIntentCreator.INSTANCE.createShareWithSubject(
- imageData.uri, imageData.subject);
- mCallbacks.onAction(shareIntent, imageData.owner, false);
-
- });
- mEditChip.setOnClickListener(v -> {
- mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_EDIT_TAPPED, 0, mPackageName);
- prepareSharedTransition();
- mCallbacks.onAction(
- ActionIntentCreator.INSTANCE.createEdit(imageData.uri, mContext),
- imageData.owner, true);
- });
- mScreenshotPreview.setOnClickListener(v -> {
- mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_PREVIEW_TAPPED, 0, mPackageName);
- prepareSharedTransition();
- mCallbacks.onAction(
- ActionIntentCreator.INSTANCE.createEdit(imageData.uri, mContext),
- imageData.owner, true);
- });
- if (mQuickShareChip != null) {
- if (imageData.quickShareAction != null) {
- mQuickShareChip.setPendingIntent(imageData.quickShareAction.actionIntent,
- () -> {
- mUiEventLogger.log(
- ScreenshotEvent.SCREENSHOT_SMART_ACTION_TAPPED, 0,
- mPackageName);
- animateDismissal();
- });
- } else {
- // hide chip and unset pending interaction if necessary, since we don't actually
- // have a useable quick share intent
- Log.wtf(TAG, "Showed quick share chip, but quick share intent was null");
- if (mPendingInteraction == PendingInteraction.QUICK_SHARE) {
- mPendingInteraction = null;
- }
- mQuickShareChip.setVisibility(GONE);
- }
- }
-
- if (mPendingInteraction != null) {
- switch (mPendingInteraction) {
- case PREVIEW:
- mScreenshotPreview.callOnClick();
- break;
- case SHARE:
- mShareChip.callOnClick();
- break;
- case EDIT:
- mEditChip.callOnClick();
- break;
- case QUICK_SHARE:
- mQuickShareChip.callOnClick();
- break;
- }
- } else {
- LayoutInflater inflater = LayoutInflater.from(mContext);
-
- for (Notification.Action smartAction : imageData.smartActions) {
- OverlayActionChip actionChip = (OverlayActionChip) inflater.inflate(
- R.layout.overlay_action_chip, mActionsView, false);
- actionChip.setText(smartAction.title);
- actionChip.setIcon(smartAction.getIcon(), false);
- actionChip.setPendingIntent(smartAction.actionIntent,
- () -> {
- mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_SMART_ACTION_TAPPED,
- 0, mPackageName);
- animateDismissal();
- });
- actionChip.setAlpha(1);
- mActionsView.addView(actionChip, mActionsView.getChildCount() - 1);
- mSmartChips.add(actionChip);
- }
- }
- }
-
- void addQuickShareChip(Notification.Action quickShareAction) {
- if (mQuickShareChip != null) {
- mSmartChips.remove(mQuickShareChip);
- mActionsView.removeView(mQuickShareChip);
- }
- if (mPendingInteraction == PendingInteraction.QUICK_SHARE) {
- mPendingInteraction = null;
- }
- if (mPendingInteraction == null) {
- LayoutInflater inflater = LayoutInflater.from(mContext);
- mQuickShareChip = (OverlayActionChip) inflater.inflate(
- R.layout.overlay_action_chip, mActionsView, false);
- mQuickShareChip.setText(quickShareAction.title);
- mQuickShareChip.setIcon(quickShareAction.getIcon(), false);
- mQuickShareChip.setOnClickListener(v -> {
- mShareChip.setIsPending(false);
- mEditChip.setIsPending(false);
- mQuickShareChip.setIsPending(true);
- mPendingInteraction = PendingInteraction.QUICK_SHARE;
- });
- mQuickShareChip.setAlpha(1);
- mActionsView.addView(mQuickShareChip);
- mSmartChips.add(mQuickShareChip);
- }
- }
-
- private Rect scrollableAreaOnScreen(ScrollCaptureResponse response) {
- Rect r = new Rect(response.getBoundsInWindow());
- Rect windowInScreen = response.getWindowBounds();
- r.offset(windowInScreen.left, windowInScreen.top);
- r.intersect(new Rect(0, 0, mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels));
- return r;
- }
-
- void startLongScreenshotTransition(Rect destination, Runnable onTransitionEnd,
- ScrollCaptureController.LongScreenshot longScreenshot) {
- mPendingSharedTransition = true;
- AnimatorSet animSet = new AnimatorSet();
-
- ValueAnimator scrimAnim = ValueAnimator.ofFloat(0, 1);
- scrimAnim.addUpdateListener(animation ->
- mScrollingScrim.setAlpha(1 - animation.getAnimatedFraction()));
-
- if (mShowScrollablePreview) {
- mScrollablePreview.setImageBitmap(longScreenshot.toBitmap());
- float startX = mScrollablePreview.getX();
- float startY = mScrollablePreview.getY();
- int[] locInScreen = mScrollablePreview.getLocationOnScreen();
- destination.offset((int) startX - locInScreen[0], (int) startY - locInScreen[1]);
- mScrollablePreview.setPivotX(0);
- mScrollablePreview.setPivotY(0);
- mScrollablePreview.setAlpha(1f);
- float currentScale = mScrollablePreview.getWidth() / (float) longScreenshot.getWidth();
- Matrix matrix = new Matrix();
- matrix.setScale(currentScale, currentScale);
- matrix.postTranslate(
- longScreenshot.getLeft() * currentScale,
- longScreenshot.getTop() * currentScale);
- mScrollablePreview.setImageMatrix(matrix);
- float destinationScale = destination.width() / (float) mScrollablePreview.getWidth();
-
- ValueAnimator previewAnim = ValueAnimator.ofFloat(0, 1);
- previewAnim.addUpdateListener(animation -> {
- float t = animation.getAnimatedFraction();
- float currScale = MathUtils.lerp(1, destinationScale, t);
- mScrollablePreview.setScaleX(currScale);
- mScrollablePreview.setScaleY(currScale);
- mScrollablePreview.setX(MathUtils.lerp(startX, destination.left, t));
- mScrollablePreview.setY(MathUtils.lerp(startY, destination.top, t));
- });
- ValueAnimator previewFadeAnim = ValueAnimator.ofFloat(1, 0);
- previewFadeAnim.addUpdateListener(animation ->
- mScrollablePreview.setAlpha(1 - animation.getAnimatedFraction()));
- animSet.play(previewAnim).with(scrimAnim).before(previewFadeAnim);
- previewAnim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- super.onAnimationEnd(animation);
- onTransitionEnd.run();
- }
- });
- } else {
- // if we switched orientations between the original screenshot and the long screenshot
- // capture, just fade out the scrim instead of running the preview animation
- animSet.play(scrimAnim);
- animSet.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- super.onAnimationEnd(animation);
- onTransitionEnd.run();
- }
- });
- }
- animSet.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- super.onAnimationEnd(animation);
- mCallbacks.onDismiss();
- }
- });
- animSet.start();
- }
-
- void prepareScrollingTransition(ScrollCaptureResponse response, Bitmap screenBitmap,
- Bitmap newBitmap, boolean screenshotTakenInPortrait) {
- mShowScrollablePreview = (screenshotTakenInPortrait == mOrientationPortrait);
-
- mScrollingScrim.setImageBitmap(newBitmap);
- mScrollingScrim.setVisibility(View.VISIBLE);
-
- if (mShowScrollablePreview) {
- Rect scrollableArea = scrollableAreaOnScreen(response);
-
- float scale = mFixedSize
- / (mOrientationPortrait ? screenBitmap.getWidth() : screenBitmap.getHeight());
- ConstraintLayout.LayoutParams params =
- (ConstraintLayout.LayoutParams) mScrollablePreview.getLayoutParams();
-
- params.width = (int) (scale * scrollableArea.width());
- params.height = (int) (scale * scrollableArea.height());
- Matrix matrix = new Matrix();
- matrix.setScale(scale, scale);
- matrix.postTranslate(-scrollableArea.left * scale, -scrollableArea.top * scale);
-
- mScrollablePreview.setTranslationX(scale
- * (mDirectionLTR ? scrollableArea.left : scrollableArea.right - getWidth()));
- mScrollablePreview.setTranslationY(scale * scrollableArea.top);
- mScrollablePreview.setImageMatrix(matrix);
- mScrollablePreview.setImageBitmap(screenBitmap);
- mScrollablePreview.setVisibility(View.VISIBLE);
- }
- mDismissButton.setVisibility(View.GONE);
- mActionsContainer.setVisibility(View.GONE);
- // set these invisible, but not gone, so that the views are laid out correctly
- mActionsContainerBackground.setVisibility(View.INVISIBLE);
- mScreenshotPreviewBorder.setVisibility(View.INVISIBLE);
- mScreenshotPreview.setVisibility(View.INVISIBLE);
- mScrollingScrim.setImageTintBlendMode(BlendMode.SRC_ATOP);
- ValueAnimator anim = ValueAnimator.ofFloat(0, .3f);
- anim.addUpdateListener(animation -> mScrollingScrim.setImageTintList(
- ColorStateList.valueOf(Color.argb((float) animation.getAnimatedValue(), 0, 0, 0))));
- anim.setDuration(200);
- anim.start();
- }
-
- void restoreNonScrollingUi() {
- mScrollChip.setVisibility(View.GONE);
- mScrollablePreview.setVisibility(View.GONE);
- mScrollingScrim.setVisibility(View.GONE);
-
- if (mAccessibilityManager.isEnabled()) {
- mDismissButton.setVisibility(View.VISIBLE);
- }
- mActionsContainer.setVisibility(View.VISIBLE);
- mActionsContainerBackground.setVisibility(View.VISIBLE);
- mScreenshotPreviewBorder.setVisibility(View.VISIBLE);
- mScreenshotPreview.setVisibility(View.VISIBLE);
- // reset the timeout
- mCallbacks.onUserInteraction();
- }
-
- boolean isDismissing() {
- return mScreenshotStatic.isDismissing();
- }
-
- boolean isPendingSharedTransition() {
- return mPendingSharedTransition;
- }
-
- void animateDismissal() {
- mScreenshotStatic.dismiss();
- }
-
- void reset() {
- if (DEBUG_UI) {
- Log.d(TAG, "reset screenshot view");
- }
- mScreenshotStatic.cancelDismissal();
- if (DEBUG_WINDOW) {
- Log.d(TAG, "removing OnComputeInternalInsetsListener");
- }
- // Make sure we clean up the view tree observer
- getViewTreeObserver().removeOnComputeInternalInsetsListener(this);
- // Clear any references to the bitmap
- mScreenshotPreview.setImageDrawable(null);
- mScreenshotPreview.setVisibility(View.INVISIBLE);
- mScreenshotPreview.setAlpha(1f);
- mScreenshotPreviewBorder.setAlpha(0);
- mScreenshotBadge.setAlpha(0f);
- mScreenshotBadge.setVisibility(View.GONE);
- mScreenshotBadge.setImageDrawable(null);
- mPendingSharedTransition = false;
- mActionsContainerBackground.setVisibility(View.INVISIBLE);
- mActionsContainer.setVisibility(View.GONE);
- mDismissButton.setVisibility(View.GONE);
- mScrollingScrim.setVisibility(View.GONE);
- mScrollablePreview.setVisibility(View.GONE);
- mScreenshotStatic.setTranslationX(0);
- mScreenshotPreview.setContentDescription(
- mContext.getResources().getString(R.string.screenshot_preview_description));
- mScreenshotPreview.setOnClickListener(null);
- mShareChip.setOnClickListener(null);
- mScrollingScrim.setVisibility(View.GONE);
- mEditChip.setOnClickListener(null);
- mShareChip.setIsPending(false);
- mEditChip.setIsPending(false);
- mPendingInteraction = null;
- for (OverlayActionChip chip : mSmartChips) {
- mActionsView.removeView(chip);
- }
- mSmartChips.clear();
- mQuickShareChip = null;
- setAlpha(1);
- mScreenshotStatic.setAlpha(1);
- mScreenshotData = null;
- }
-
- private void prepareSharedTransition() {
- mPendingSharedTransition = true;
- // fade out non-preview UI
- createScreenshotFadeDismissAnimation().start();
- }
-
- ValueAnimator createScreenshotFadeDismissAnimation() {
- ValueAnimator alphaAnim = ValueAnimator.ofFloat(0, 1);
- alphaAnim.addUpdateListener(animation -> {
- float alpha = 1 - animation.getAnimatedFraction();
- mDismissButton.setAlpha(alpha);
- mActionsContainerBackground.setAlpha(alpha);
- mActionsContainer.setAlpha(alpha);
- mScreenshotPreviewBorder.setAlpha(alpha);
- mScreenshotBadge.setAlpha(alpha);
- });
- alphaAnim.setDuration(600);
- return alphaAnim;
- }
-
- /**
- * Create a drawable using the size of the bitmap and insets as the fractional inset parameters.
- */
- private static Drawable createScreenDrawable(Resources res, Bitmap bitmap, Insets insets) {
- int insettedWidth = bitmap.getWidth() - insets.left - insets.right;
- int insettedHeight = bitmap.getHeight() - insets.top - insets.bottom;
-
- BitmapDrawable bitmapDrawable = new BitmapDrawable(res, bitmap);
- if (insettedHeight == 0 || insettedWidth == 0 || bitmap.getWidth() == 0
- || bitmap.getHeight() == 0) {
- Log.e(TAG, "Can't create inset drawable, using 0 insets bitmap and insets create "
- + "degenerate region: " + bitmap.getWidth() + "x" + bitmap.getHeight() + " "
- + bitmapDrawable);
- return bitmapDrawable;
- }
-
- InsetDrawable insetDrawable = new InsetDrawable(bitmapDrawable,
- -1f * insets.left / insettedWidth,
- -1f * insets.top / insettedHeight,
- -1f * insets.right / insettedWidth,
- -1f * insets.bottom / insettedHeight);
-
- if (insets.left < 0 || insets.top < 0 || insets.right < 0 || insets.bottom < 0) {
- // Are any of the insets negative, meaning the bitmap is smaller than the bounds so need
- // to fill in the background of the drawable.
- return new LayerDrawable(new Drawable[]{
- new ColorDrawable(Color.BLACK), insetDrawable});
- } else {
- return insetDrawable;
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotViewProxy.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotViewProxy.kt
deleted file mode 100644
index df93a5e56c22..000000000000
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotViewProxy.kt
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.screenshot
-
-import android.animation.Animator
-import android.app.Notification
-import android.content.Context
-import android.graphics.Bitmap
-import android.graphics.Rect
-import android.view.ScrollCaptureResponse
-import android.view.View
-import android.view.ViewGroup
-import android.view.WindowInsets
-import com.android.systemui.screenshot.scroll.ScrollCaptureController
-
-/** Abstraction of the surface between ScreenshotController and ScreenshotView */
-interface ScreenshotViewProxy {
- val view: ViewGroup
- val screenshotPreview: View
-
- var packageName: String
- var callbacks: ScreenshotView.ScreenshotViewCallback?
- var screenshot: ScreenshotData?
-
- val isAttachedToWindow: Boolean
- val isDismissing: Boolean
- val isPendingSharedTransition: Boolean
-
- fun reset()
- fun updateInsets(insets: WindowInsets)
- fun updateOrientation(insets: WindowInsets)
- fun createScreenshotDropInAnimation(screenRect: Rect, showFlash: Boolean): Animator
- fun addQuickShareChip(quickShareAction: Notification.Action)
- fun setChipIntents(imageData: ScreenshotController.SavedImageData)
- fun requestDismissal(event: ScreenshotEvent?)
-
- fun showScrollChip(packageName: String, onClick: Runnable)
- fun hideScrollChip()
- fun prepareScrollingTransition(
- response: ScrollCaptureResponse,
- screenBitmap: Bitmap,
- newScreenshot: Bitmap,
- screenshotTakenInPortrait: Boolean,
- onTransitionPrepared: Runnable,
- )
- fun startLongScreenshotTransition(
- transitionDestination: Rect,
- onTransitionEnd: Runnable,
- longScreenshot: ScrollCaptureController.LongScreenshot
- )
- fun restoreNonScrollingUi()
- fun fadeForSharedTransition()
-
- fun stopInputListening()
- fun requestFocus()
- fun announceForAccessibility(string: String)
- fun prepareEntranceAnimation(runnable: Runnable)
-
- interface Factory {
- fun getProxy(context: Context, displayId: Int): ScreenshotViewProxy
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotExecutor.kt b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotExecutor.kt
index 2699657847b9..07f6e85cfad8 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotExecutor.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotExecutor.kt
@@ -219,7 +219,7 @@ constructor(
}
private fun getScreenshotController(display: Display): ScreenshotController {
- val controller = screenshotController ?: screenshotControllerFactory.create(display, false)
+ val controller = screenshotController ?: screenshotControllerFactory.create(display)
screenshotController = controller
return controller
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsViewModel.java b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsViewModel.java
index 8c833eccb1fb..bd9e295b58f8 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsViewModel.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsViewModel.java
@@ -33,6 +33,7 @@ import android.content.ClipData;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.graphics.Bitmap;
import android.graphics.HardwareRenderer;
import android.graphics.RecordingCanvas;
@@ -267,6 +268,8 @@ final class AppClipsViewModel extends ViewModel {
}
private boolean canAppStartThroughLauncher(String packageName) {
+ // Use Intent.resolveActivity API to check if the intent resolves as that is what Android
+ // uses internally when apps use Context.startActivity.
return getMainLauncherIntentForPackage(packageName).resolveActivity(mPackageManager)
!= null;
}
@@ -366,10 +369,19 @@ final class AppClipsViewModel extends ViewModel {
return taskInfo.topActivityInfo.loadLabel(mPackageManager).toString();
}
- private Intent getMainLauncherIntentForPackage(String packageName) {
- return new Intent(ACTION_MAIN)
- .addCategory(CATEGORY_LAUNCHER)
- .setPackage(packageName);
+ private Intent getMainLauncherIntentForPackage(String pkgName) {
+ Intent intent = new Intent(ACTION_MAIN).addCategory(CATEGORY_LAUNCHER).setPackage(pkgName);
+
+ // Not all apps use DEFAULT_CATEGORY for their main launcher activity so the exact component
+ // needs to be queried and set on the Intent in order for note-taking apps to be able to
+ // start this intent. When starting an activity with an implicit intent, Android adds the
+ // DEFAULT_CATEGORY flag otherwise it fails to resolve the intent.
+ ResolveInfo resolvedActivity = mPackageManager.resolveActivity(intent, /* flags= */ 0);
+ if (resolvedActivity != null) {
+ intent.setComponent(resolvedActivity.getComponentInfo().getComponentName());
+ }
+
+ return intent;
}
/** Helper factory to help with injecting {@link AppClipsViewModel}. */
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/dagger/ScreenshotModule.java b/packages/SystemUI/src/com/android/systemui/screenshot/dagger/ScreenshotModule.java
index 8235325fffad..682f848bfaad 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/dagger/ScreenshotModule.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/dagger/ScreenshotModule.java
@@ -16,23 +16,18 @@
package com.android.systemui.screenshot.dagger;
-import static com.android.systemui.Flags.screenshotShelfUi2;
-
import android.app.Service;
import android.view.accessibility.AccessibilityManager;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.screenshot.ImageCapture;
import com.android.systemui.screenshot.ImageCaptureImpl;
-import com.android.systemui.screenshot.LegacyScreenshotViewProxy;
import com.android.systemui.screenshot.ScreenshotPolicy;
import com.android.systemui.screenshot.ScreenshotPolicyImpl;
-import com.android.systemui.screenshot.ScreenshotShelfViewProxy;
import com.android.systemui.screenshot.ScreenshotSoundController;
import com.android.systemui.screenshot.ScreenshotSoundControllerImpl;
import com.android.systemui.screenshot.ScreenshotSoundProvider;
import com.android.systemui.screenshot.ScreenshotSoundProviderImpl;
-import com.android.systemui.screenshot.ScreenshotViewProxy;
import com.android.systemui.screenshot.TakeScreenshotExecutor;
import com.android.systemui.screenshot.TakeScreenshotExecutorImpl;
import com.android.systemui.screenshot.TakeScreenshotService;
@@ -95,15 +90,4 @@ public abstract class ScreenshotModule {
AccessibilityManager accessibilityManager) {
return new ScreenshotViewModel(accessibilityManager);
}
-
- @Provides
- static ScreenshotViewProxy.Factory providesScreenshotViewProxyFactory(
- ScreenshotShelfViewProxy.Factory shelfScreenshotViewProxyFactory,
- LegacyScreenshotViewProxy.Factory legacyScreenshotViewProxyFactory) {
- if (screenshotShelfUi2()) {
- return shelfScreenshotViewProxyFactory;
- } else {
- return legacyScreenshotViewProxyFactory;
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 04de2c220a6b..c1caeed05cb6 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -1774,8 +1774,9 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
// the small clock here
// With migrateClocksToBlueprint, weather clock will have behaviors similar to other clocks
if (!MigrateClocksToBlueprint.isEnabled()) {
+ boolean bypassEnabled = mKeyguardBypassController.getBypassEnabled();
if (mKeyguardStatusViewController.isLargeClockBlockingNotificationShelf()
- && hasVisibleNotifications() && isOnAod()) {
+ && hasVisibleNotifications() && (isOnAod() || bypassEnabled)) {
return SMALL;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeRepository.kt b/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeRepository.kt
index 4d43ad52019a..a4fed873362b 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeRepository.kt
@@ -19,8 +19,6 @@ import android.content.Context
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.res.R
-import com.android.systemui.shade.shared.flag.DualShade
-import com.android.systemui.shade.shared.model.ShadeMode
import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
@@ -105,18 +103,26 @@ interface ShadeRepository {
@Deprecated("Use ShadeInteractor.isQsBypassingShade instead")
val legacyExpandImmediate: StateFlow<Boolean>
- val shadeMode: StateFlow<ShadeMode>
-
/** Whether dual shade should be aligned to the bottom (true) or to the top (false). */
val isDualShadeAlignedToBottom: Boolean
+ /**
+ * Whether the shade layout should be wide (true) or narrow (false).
+ *
+ * In a wide layout, notifications and quick settings each take up only half the screen width
+ * (whether they are shown at the same time or not). In a narrow layout, they can each be as
+ * wide as the entire screen.
+ */
+ val isShadeLayoutWide: StateFlow<Boolean>
+
/** True when QS is taking up the entire screen, i.e. fully expanded on a non-unfolded phone. */
@Deprecated("Use ShadeInteractor instead") val legacyQsFullscreen: StateFlow<Boolean>
/** NPVC.mClosing as a flow. */
@Deprecated("Use ShadeAnimationInteractor instead") val legacyIsClosing: StateFlow<Boolean>
- fun setShadeMode(mode: ShadeMode)
+ /** Sets whether the shade layout should be wide (true) or narrow (false). */
+ fun setShadeLayoutWide(isShadeLayoutWide: Boolean)
/** Sets whether a closing animation is happening. */
@Deprecated("Use ShadeAnimationInteractor instead") fun setLegacyIsClosing(isClosing: Boolean)
@@ -183,6 +189,7 @@ interface ShadeRepository {
class ShadeRepositoryImpl @Inject constructor(@Application applicationContext: Context) :
ShadeRepository {
private val _qsExpansion = MutableStateFlow(0f)
+ @Deprecated("Use ShadeInteractor.qsExpansion instead")
override val qsExpansion: StateFlow<Float> = _qsExpansion.asStateFlow()
private val _lockscreenShadeExpansion = MutableStateFlow(0f)
@@ -204,6 +211,7 @@ class ShadeRepositoryImpl @Inject constructor(@Application applicationContext: C
@Deprecated("Use ShadeInteractor instead")
override val legacyShadeTracking: StateFlow<Boolean> = _legacyShadeTracking.asStateFlow()
+ @Deprecated("Use ShadeInteractor.isUserInteractingWithShade instead")
override val legacyLockscreenShadeTracking = MutableStateFlow(false)
private val _legacyQsTracking = MutableStateFlow(false)
@@ -227,20 +235,22 @@ class ShadeRepositoryImpl @Inject constructor(@Application applicationContext: C
@Deprecated("Use ShadeInteractor instead")
override val legacyQsFullscreen: StateFlow<Boolean> = _legacyQsFullscreen.asStateFlow()
- val _shadeMode = MutableStateFlow(if (DualShade.isEnabled) ShadeMode.Dual else ShadeMode.Single)
- override val shadeMode: StateFlow<ShadeMode> = _shadeMode.asStateFlow()
+ private val _isShadeLayoutWide = MutableStateFlow(false)
+ override val isShadeLayoutWide: StateFlow<Boolean> = _isShadeLayoutWide.asStateFlow()
override val isDualShadeAlignedToBottom =
applicationContext.resources.getBoolean(R.bool.config_dualShadeAlignedToBottom)
- override fun setShadeMode(shadeMode: ShadeMode) {
- _shadeMode.value = shadeMode
+ override fun setShadeLayoutWide(isShadeLayoutWide: Boolean) {
+ _isShadeLayoutWide.value = isShadeLayoutWide
}
+ @Deprecated("Use ShadeInteractor instead")
override fun setLegacyQsFullscreen(legacyQsFullscreen: Boolean) {
_legacyQsFullscreen.value = legacyQsFullscreen
}
+ @Deprecated("Use ShadeInteractor instead")
override fun setLegacyExpandImmediate(legacyExpandImmediate: Boolean) {
_legacyExpandImmediate.value = legacyExpandImmediate
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt
index ef0a842ecc0c..45f359efbb7a 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt
@@ -52,9 +52,25 @@ interface ShadeInteractor : BaseShadeInteractor {
/** Are touches allowed on the notification panel? */
val isShadeTouchable: Flow<Boolean>
- /** Emits true if the shade can be expanded from QQS to QS and false otherwise. */
+ /** Whether the shade can be expanded from QQS to QS. */
val isExpandToQsEnabled: Flow<Boolean>
+ /**
+ * The version of the shade layout to use.
+ *
+ * Note: Most likely, you want to read [isShadeLayoutWide] instead of this.
+ */
+ val shadeMode: StateFlow<ShadeMode>
+
+ /**
+ * Whether the shade layout should be wide (true) or narrow (false).
+ *
+ * In a wide layout, notifications and quick settings each take up only half the screen width
+ * (whether they are shown at the same time or not). In a narrow layout, they can each be as
+ * wide as the entire screen.
+ */
+ val isShadeLayoutWide: StateFlow<Boolean>
+
/** How to align the shade content. */
val shadeAlignment: ShadeAlignment
}
@@ -113,8 +129,6 @@ interface BaseShadeInteractor {
* animating.
*/
val isUserInteractingWithQs: Flow<Boolean>
-
- val shadeMode: StateFlow<ShadeMode>
}
fun createAnyExpansionFlow(
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorEmptyImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorEmptyImpl.kt
index 6226d077b135..e77aca93aeca 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorEmptyImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorEmptyImpl.kt
@@ -47,5 +47,6 @@ class ShadeInteractorEmptyImpl @Inject constructor() : ShadeInteractor {
override val isShadeTouchable: Flow<Boolean> = inactiveFlowBoolean
override val isExpandToQsEnabled: Flow<Boolean> = inactiveFlowBoolean
override val shadeMode: StateFlow<ShadeMode> = MutableStateFlow(ShadeMode.Single)
+ override val isShadeLayoutWide: StateFlow<Boolean> = inactiveFlowBoolean
override val shadeAlignment: ShadeAlignment = ShadeAlignment.Top
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt
index 55f019b01164..684a4845144e 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt
@@ -25,7 +25,9 @@ import com.android.systemui.keyguard.shared.model.Edge
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.shade.data.repository.ShadeRepository
+import com.android.systemui.shade.shared.flag.DualShade
import com.android.systemui.shade.shared.model.ShadeAlignment
+import com.android.systemui.shade.shared.model.ShadeMode
import com.android.systemui.statusbar.disableflags.data.repository.DisableFlagsRepository
import com.android.systemui.statusbar.phone.DozeParameters
import com.android.systemui.statusbar.policy.data.repository.UserSetupRepository
@@ -60,8 +62,7 @@ constructor(
) : ShadeInteractor, BaseShadeInteractor by baseShadeInteractor {
override val isShadeEnabled: StateFlow<Boolean> =
disableFlagsRepository.disableFlags
- .map { isDisabledByFlags -> isDisabledByFlags.isShadeEnabled() }
- .distinctUntilChanged()
+ .map { it.isShadeEnabled() }
.stateIn(scope, SharingStarted.Eagerly, initialValue = false)
override val isQsEnabled: StateFlow<Boolean> =
@@ -102,6 +103,17 @@ constructor(
}
}
+ override val isShadeLayoutWide: StateFlow<Boolean> = shadeRepository.isShadeLayoutWide
+
+ override val shadeMode: StateFlow<ShadeMode> =
+ isShadeLayoutWide
+ .map(this::determineShadeMode)
+ .stateIn(
+ scope,
+ SharingStarted.Eagerly,
+ initialValue = determineShadeMode(isShadeLayoutWide.value)
+ )
+
override val shadeAlignment: ShadeAlignment =
if (shadeRepository.isDualShadeAlignedToBottom) {
ShadeAlignment.Bottom
@@ -125,4 +137,12 @@ constructor(
disableFlags.isQuickSettingsEnabled() &&
!isDozing
}
+
+ private fun determineShadeMode(isShadeLayoutWide: Boolean): ShadeMode {
+ return when {
+ DualShade.isEnabled -> ShadeMode.Dual
+ isShadeLayoutWide -> ShadeMode.Split
+ else -> ShadeMode.Single
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorLegacyImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorLegacyImpl.kt
index 7d46d2ba17da..f39ee9afd039 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorLegacyImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorLegacyImpl.kt
@@ -21,7 +21,6 @@ import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.data.repository.KeyguardRepository
import com.android.systemui.keyguard.shared.model.StatusBarState
import com.android.systemui.shade.data.repository.ShadeRepository
-import com.android.systemui.shade.shared.model.ShadeMode
import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
@@ -105,8 +104,6 @@ constructor(
override val isUserInteractingWithQs: Flow<Boolean> =
userInteractingFlow(repository.legacyQsTracking, repository.qsExpansion)
- override val shadeMode: StateFlow<ShadeMode> = repository.shadeMode
-
/**
* Return a flow for whether a user is interacting with an expandable shade component using
* tracking and expansion flows. NOTE: expansion must be a `StateFlow` to guarantee that
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImpl.kt
index d5b4f4d7e623..b2142a515923 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImpl.kt
@@ -22,8 +22,6 @@ import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.shared.model.SceneFamilies
-import com.android.systemui.shade.data.repository.ShadeRepository
-import com.android.systemui.shade.shared.model.ShadeMode
import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor
import com.android.systemui.utils.coroutines.flow.flatMapLatestConflated
import javax.inject.Inject
@@ -45,10 +43,7 @@ constructor(
@Application scope: CoroutineScope,
sceneInteractor: SceneInteractor,
sharedNotificationContainerInteractor: SharedNotificationContainerInteractor,
- shadeRepository: ShadeRepository,
) : BaseShadeInteractor {
- override val shadeMode: StateFlow<ShadeMode> = shadeRepository.shadeMode
-
override val shadeExpansion: StateFlow<Float> =
sceneBasedExpansion(sceneInteractor, SceneFamilies.NotifShade)
.stateIn(scope, SharingStarted.Eagerly, 0f)
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/startable/ShadeStartable.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/startable/ShadeStartable.kt
index 354d379d2ea2..5eb3a1cc1348 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/startable/ShadeStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/startable/ShadeStartable.kt
@@ -29,8 +29,6 @@ import com.android.systemui.shade.ShadeExpansionStateManager
import com.android.systemui.shade.TouchLogger.Companion.logTouchesTo
import com.android.systemui.shade.data.repository.ShadeRepository
import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor
-import com.android.systemui.shade.shared.flag.DualShade
-import com.android.systemui.shade.shared.model.ShadeMode
import com.android.systemui.shade.transition.ScrimShadeTransitionController
import com.android.systemui.statusbar.PulseExpansionHandler
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
@@ -40,7 +38,6 @@ import javax.inject.Provider
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.launchIn
-import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.launch
@@ -63,7 +60,7 @@ constructor(
) : CoreStartable {
override fun start() {
- hydrateShadeMode()
+ hydrateShadeLayoutWidth()
hydrateShadeExpansionStateManager()
logTouchesTo(touchLog)
scrimShadeTransitionController.init()
@@ -86,22 +83,17 @@ constructor(
}
}
- private fun hydrateShadeMode() {
- if (DualShade.isEnabled) {
- shadeRepository.setShadeMode(ShadeMode.Dual)
- return
- }
+ private fun hydrateShadeLayoutWidth() {
applicationScope.launch {
configurationRepository.onAnyConfigurationChange
// Force initial collection.
.onStart { emit(Unit) }
- .map { applicationContext.resources }
- .map { resources ->
- splitShadeStateController.shouldUseSplitNotificationShade(resources)
- }
- .collect { isSplitShade ->
- shadeRepository.setShadeMode(
- if (isSplitShade) ShadeMode.Split else ShadeMode.Single
+ .collect {
+ val resources = applicationContext.resources
+ // The configuration for 'shouldUseSplitNotificationShade' dictates the width of
+ // the shade in both split-shade and dual-shade modes.
+ shadeRepository.setShadeLayoutWide(
+ splitShadeStateController.shouldUseSplitNotificationShade(resources)
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/shared/model/ShadeMode.kt b/packages/SystemUI/src/com/android/systemui/shade/shared/model/ShadeMode.kt
index 8214a24a9a38..a8199a402ef1 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/shared/model/ShadeMode.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/shared/model/ShadeMode.kt
@@ -29,6 +29,8 @@ sealed interface ShadeMode {
/**
* The split shade where, on large screens and unfolded foldables, the QS and notification parts
* are placed side-by-side and expand/collapse as a single panel.
+ *
+ * Note: This isn't the only mode where the shade is wide.
*/
data object Split : ShadeMode
diff --git a/packages/SystemUI/src/com/android/systemui/smartspace/dagger/SmartspaceModule.kt b/packages/SystemUI/src/com/android/systemui/smartspace/dagger/SmartspaceModule.kt
index 2f58b35ae182..ea4e065be84b 100644
--- a/packages/SystemUI/src/com/android/systemui/smartspace/dagger/SmartspaceModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/smartspace/dagger/SmartspaceModule.kt
@@ -18,51 +18,35 @@ package com.android.systemui.smartspace.dagger
import com.android.systemui.plugins.BcSmartspaceDataPlugin
import com.android.systemui.smartspace.SmartspacePrecondition
import com.android.systemui.smartspace.SmartspaceTargetFilter
-import com.android.systemui.smartspace.data.repository.SmartspaceRepositoryModule
import com.android.systemui.smartspace.preconditions.LockscreenPrecondition
import dagger.Binds
import dagger.BindsOptionalOf
import dagger.Module
import javax.inject.Named
-@Module(subcomponents = [SmartspaceViewComponent::class],
- includes = [SmartspaceRepositoryModule::class])
+@Module(subcomponents = [SmartspaceViewComponent::class])
abstract class SmartspaceModule {
@Module
companion object {
- /**
- * The BcSmartspaceDataProvider for dreams.
- */
+ /** The BcSmartspaceDataProvider for dreams. */
const val DREAM_SMARTSPACE_DATA_PLUGIN = "dreams_smartspace_data_plugin"
- /**
- * The BcSmartspaceDataPlugin for the standalone weather on dream.
- */
+ /** The BcSmartspaceDataPlugin for the standalone weather on dream. */
const val DREAM_WEATHER_SMARTSPACE_DATA_PLUGIN = "dream_weather_smartspace_data_plugin"
- /**
- * The target filter for smartspace over lockscreen.
- */
+ /** The target filter for smartspace over lockscreen. */
const val LOCKSCREEN_SMARTSPACE_TARGET_FILTER = "lockscreen_smartspace_target_filter"
- /**
- * The precondition for smartspace over lockscreen
- */
+ /** The precondition for smartspace over lockscreen */
const val LOCKSCREEN_SMARTSPACE_PRECONDITION = "lockscreen_smartspace_precondition"
- /**
- * The BcSmartspaceDataPlugin for the standalone date (+alarm+dnd).
- */
+ /** The BcSmartspaceDataPlugin for the standalone date (+alarm+dnd). */
const val DATE_SMARTSPACE_DATA_PLUGIN = "date_smartspace_data_plugin"
- /**
- * The BcSmartspaceDataPlugin for the standalone weather.
- */
+ /** The BcSmartspaceDataPlugin for the standalone weather. */
const val WEATHER_SMARTSPACE_DATA_PLUGIN = "weather_smartspace_data_plugin"
- /**
- * The BcSmartspaceDataProvider for the glanceable hub.
- */
+ /** The BcSmartspaceDataProvider for the glanceable hub. */
const val GLANCEABLE_HUB_SMARTSPACE_DATA_PLUGIN = "glanceable_hub_smartspace_data_plugin"
}
diff --git a/packages/SystemUI/src/com/android/systemui/smartspace/data/repository/SmartspaceRepository.kt b/packages/SystemUI/src/com/android/systemui/smartspace/data/repository/SmartspaceRepository.kt
deleted file mode 100644
index 52a1c1555591..000000000000
--- a/packages/SystemUI/src/com/android/systemui/smartspace/data/repository/SmartspaceRepository.kt
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.smartspace.data.repository
-
-import android.app.smartspace.SmartspaceTarget
-import android.os.Parcelable
-import android.widget.RemoteViews
-import com.android.systemui.communal.smartspace.CommunalSmartspaceController
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.plugins.BcSmartspaceDataPlugin
-import java.util.concurrent.Executor
-import javax.inject.Inject
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.onCompletion
-import kotlinx.coroutines.flow.onStart
-
-interface SmartspaceRepository {
- /** Whether [RemoteViews] are passed through smartspace targets. */
- val isSmartspaceRemoteViewsEnabled: Boolean
-
- /** Smartspace targets for the communal surface. */
- val communalSmartspaceTargets: Flow<List<SmartspaceTarget>>
-}
-
-@SysUISingleton
-class SmartspaceRepositoryImpl
-@Inject
-constructor(
- private val communalSmartspaceController: CommunalSmartspaceController,
- @Main private val uiExecutor: Executor,
-) : SmartspaceRepository, BcSmartspaceDataPlugin.SmartspaceTargetListener {
-
- override val isSmartspaceRemoteViewsEnabled: Boolean
- get() = android.app.smartspace.flags.Flags.remoteViews()
-
- private val _communalSmartspaceTargets: MutableStateFlow<List<SmartspaceTarget>> =
- MutableStateFlow(emptyList())
- override val communalSmartspaceTargets: Flow<List<SmartspaceTarget>> =
- _communalSmartspaceTargets
- .onStart {
- uiExecutor.execute {
- communalSmartspaceController.addListener(
- listener = this@SmartspaceRepositoryImpl
- )
- }
- }
- .onCompletion {
- uiExecutor.execute {
- communalSmartspaceController.removeListener(
- listener = this@SmartspaceRepositoryImpl
- )
- }
- }
-
- override fun onSmartspaceTargetsUpdated(targetsNullable: MutableList<out Parcelable>?) {
- targetsNullable?.let { targets ->
- _communalSmartspaceTargets.value = targets.filterIsInstance<SmartspaceTarget>()
- }
- ?: run { _communalSmartspaceTargets.value = emptyList() }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java
index 342ec0dc228d..c997ac5ad9df 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java
@@ -19,6 +19,7 @@ package com.android.systemui.statusbar;
import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_YES;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
+import static com.android.systemui.Flags.fetchBookmarksXmlKeyboardShortcuts;
import static com.android.systemui.Flags.validateKeyboardShortcutHelperIconUri;
import android.annotation.NonNull;
@@ -149,7 +150,7 @@ public final class KeyboardShortcutListSearch {
private KeyCharacterMap mBackupKeyCharacterMap;
@VisibleForTesting
- KeyboardShortcutListSearch(Context context, WindowManager windowManager) {
+ KeyboardShortcutListSearch(Context context, WindowManager windowManager, int deviceId) {
this.mContext = new ContextThemeWrapper(
context, R.style.KeyboardShortcutHelper);
this.mPackageManager = AppGlobals.getPackageManager();
@@ -159,12 +160,12 @@ public final class KeyboardShortcutListSearch {
this.mWindowManager = mContext.getSystemService(WindowManager.class);
}
loadResources(this.mContext);
- createHardcodedShortcuts();
+ createHardcodedShortcuts(deviceId);
}
- private static KeyboardShortcutListSearch getInstance(Context context) {
+ private static KeyboardShortcutListSearch getInstance(Context context, int deviceId) {
if (sInstance == null) {
- sInstance = new KeyboardShortcutListSearch(context, null);
+ sInstance = new KeyboardShortcutListSearch(context, null, deviceId);
}
return sInstance;
}
@@ -176,7 +177,7 @@ public final class KeyboardShortcutListSearch {
if (sInstance != null && !sInstance.mContext.equals(context)) {
dismiss();
}
- getInstance(context).showKeyboardShortcuts(deviceId);
+ getInstance(context, deviceId).showKeyboardShortcuts(deviceId);
}
}
@@ -274,7 +275,8 @@ public final class KeyboardShortcutListSearch {
context.getString(R.string.keyboard_key_button_template, "Mode"));
mSpecialCharacterNames.put(
KeyEvent.KEYCODE_FORWARD_DEL, context.getString(R.string.keyboard_key_forward_del));
- mSpecialCharacterNames.put(KeyEvent.KEYCODE_ESCAPE, "Esc");
+ mSpecialCharacterNames.put(
+ KeyEvent.KEYCODE_ESCAPE, context.getString(R.string.keyboard_key_esc));
mSpecialCharacterNames.put(KeyEvent.KEYCODE_SYSRQ, "SysRq");
mSpecialCharacterNames.put(KeyEvent.KEYCODE_BREAK, "Break");
mSpecialCharacterNames.put(KeyEvent.KEYCODE_SCROLL_LOCK, "Scroll Lock");
@@ -366,7 +368,7 @@ public final class KeyboardShortcutListSearch {
KeyEvent.META_META_ON, context.getDrawable(R.drawable.ic_ksh_key_meta));
}
- private void createHardcodedShortcuts() {
+ private void createHardcodedShortcuts(int deviceId) {
// Add system shortcuts
mKeySearchResultMap.put(SHORTCUT_SYSTEM_INDEX, true);
mSystemGroup.add(getMultiMappingSystemShortcuts(mContext));
@@ -376,7 +378,7 @@ public final class KeyboardShortcutListSearch {
mInputGroup.add(getMultiMappingInputShortcuts(mContext));
// Add open apps shortcuts
final List<KeyboardShortcutMultiMappingGroup> appShortcuts =
- Arrays.asList(getDefaultMultiMappingApplicationShortcuts());
+ Arrays.asList(getDefaultMultiMappingApplicationShortcuts(deviceId));
if (appShortcuts != null && !appShortcuts.isEmpty()) {
mOpenAppsGroup = appShortcuts;
mKeySearchResultMap.put(SHORTCUT_OPENAPPS_INDEX, true);
@@ -738,35 +740,50 @@ public final class KeyboardShortcutListSearch {
shortcutMultiMappingInfoList);
}
- private KeyboardShortcutMultiMappingGroup getDefaultMultiMappingApplicationShortcuts() {
- final int userId = mContext.getUserId();
- PackageInfo assistPackageInfo = getAssistPackageInfo(mContext, mPackageManager, userId);
- CharSequence categoryTitle =
- mContext.getString(R.string.keyboard_shortcut_group_applications);
+ private KeyboardShortcutMultiMappingGroup getDefaultMultiMappingApplicationShortcuts(
+ int deviceId) {
List<ShortcutMultiMappingInfo> shortcutMultiMappingInfos = new ArrayList<>();
-
- String[] intentCategories = {
- Intent.CATEGORY_APP_BROWSER,
- Intent.CATEGORY_APP_CONTACTS,
- Intent.CATEGORY_APP_EMAIL,
- Intent.CATEGORY_APP_CALENDAR,
- Intent.CATEGORY_APP_MAPS,
- Intent.CATEGORY_APP_MUSIC,
- Intent.CATEGORY_APP_MESSAGING,
- Intent.CATEGORY_APP_CALCULATOR,
-
- };
- String[] shortcutLabels = {
- mContext.getString(R.string.keyboard_shortcut_group_applications_browser),
- mContext.getString(R.string.keyboard_shortcut_group_applications_contacts),
- mContext.getString(R.string.keyboard_shortcut_group_applications_email),
- mContext.getString(R.string.keyboard_shortcut_group_applications_calendar),
- mContext.getString(R.string.keyboard_shortcut_group_applications_maps),
- mContext.getString(R.string.keyboard_shortcut_group_applications_music),
- mContext.getString(R.string.keyboard_shortcut_group_applications_sms),
- mContext.getString(R.string.keyboard_shortcut_group_applications_calculator)
- };
- int[] keyCodes = {
+ CharSequence categoryTitle;
+ if (fetchBookmarksXmlKeyboardShortcuts()) {
+ KeyboardShortcutGroup apps =
+ mWindowManager.getApplicationLaunchKeyboardShortcuts(deviceId);
+ List<KeyboardShortcutMultiMappingGroup> shortcuts =
+ reMapToKeyboardShortcutMultiMappingGroup(Arrays.asList(apps));
+ for (KeyboardShortcutMultiMappingGroup group : shortcuts) {
+ for (ShortcutMultiMappingInfo keyboardShortcutInfo : group.getItems()) {
+ shortcutMultiMappingInfos.add(keyboardShortcutInfo);
+ }
+ }
+ categoryTitle = apps.getLabel();
+ } else {
+ // Show shortcuts based on AOSP bookmarks.xml
+ categoryTitle = mContext.getString(R.string.keyboard_shortcut_group_applications);
+ final int userId = mContext.getUserId();
+ PackageInfo assistPackageInfo =
+ getAssistPackageInfo(mContext, mPackageManager, userId);
+
+ String[] intentCategories = {
+ Intent.CATEGORY_APP_BROWSER,
+ Intent.CATEGORY_APP_CONTACTS,
+ Intent.CATEGORY_APP_EMAIL,
+ Intent.CATEGORY_APP_CALENDAR,
+ Intent.CATEGORY_APP_MAPS,
+ Intent.CATEGORY_APP_MUSIC,
+ Intent.CATEGORY_APP_MESSAGING,
+ Intent.CATEGORY_APP_CALCULATOR,
+ };
+ String[] shortcutLabels = {
+ mContext.getString(R.string.keyboard_shortcut_group_applications_browser),
+ mContext.getString(R.string.keyboard_shortcut_group_applications_contacts),
+ mContext.getString(R.string.keyboard_shortcut_group_applications_email),
+ mContext.getString(R.string.keyboard_shortcut_group_applications_calendar),
+ mContext.getString(R.string.keyboard_shortcut_group_applications_maps),
+ mContext.getString(R.string.keyboard_shortcut_group_applications_music),
+ mContext.getString(R.string.keyboard_shortcut_group_applications_sms),
+ mContext.getString(R.string.keyboard_shortcut_group_applications_calculator)
+ };
+
+ int[] keyCodes = {
KeyEvent.KEYCODE_B,
KeyEvent.KEYCODE_C,
KeyEvent.KEYCODE_E,
@@ -775,52 +792,44 @@ public final class KeyboardShortcutListSearch {
KeyEvent.KEYCODE_P,
KeyEvent.KEYCODE_S,
KeyEvent.KEYCODE_U,
- };
+ };
- // Assist.
- if (assistPackageInfo != null) {
+ // Assist.
if (assistPackageInfo != null) {
- final Icon assistIcon = Icon.createWithResource(
- assistPackageInfo.applicationInfo.packageName,
- assistPackageInfo.applicationInfo.icon);
- CharSequence assistLabel =
- mContext.getString(R.string.keyboard_shortcut_group_applications_assist);
- KeyboardShortcutInfo assistShortcutInfo = new KeyboardShortcutInfo(
- assistLabel,
- assistIcon,
- KeyEvent.KEYCODE_A,
- KeyEvent.META_META_ON);
- shortcutMultiMappingInfos.add(
- new ShortcutMultiMappingInfo(
- assistLabel,
- assistIcon,
- Arrays.asList(new ShortcutKeyGroup(assistShortcutInfo, null))));
+ if (assistPackageInfo != null) {
+ final Icon assistIcon = Icon.createWithResource(
+ assistPackageInfo.applicationInfo.packageName,
+ assistPackageInfo.applicationInfo.icon);
+ CharSequence assistLabel = mContext.getString(
+ R.string.keyboard_shortcut_group_applications_assist);
+ KeyboardShortcutInfo assistShortcutInfo = new KeyboardShortcutInfo(
+ assistLabel,
+ assistIcon,
+ KeyEvent.KEYCODE_A,
+ KeyEvent.META_META_ON);
+ shortcutMultiMappingInfos.add(
+ new ShortcutMultiMappingInfo(
+ assistLabel,
+ assistIcon,
+ Arrays.asList(new ShortcutKeyGroup(assistShortcutInfo, null))));
+ }
}
- }
- // Browser (Chrome as default): Meta + B
- // Contacts: Meta + C
- // Email (Gmail as default): Meta + E
- // Gmail: Meta + G
- // Calendar: Meta + K
- // Maps: Meta + M
- // Music: Meta + P
- // SMS: Meta + S
- // Calculator: Meta + U
- for (int i = 0; i < shortcutLabels.length; i++) {
- final Icon icon = getIconForIntentCategory(intentCategories[i], userId);
- if (icon != null) {
- CharSequence label =
- shortcutLabels[i];
- KeyboardShortcutInfo keyboardShortcutInfo = new KeyboardShortcutInfo(
- label,
- icon,
- keyCodes[i],
- KeyEvent.META_META_ON);
- List<ShortcutKeyGroup> shortcutKeyGroups =
- Arrays.asList(new ShortcutKeyGroup(keyboardShortcutInfo, null));
- shortcutMultiMappingInfos.add(
- new ShortcutMultiMappingInfo(label, icon, shortcutKeyGroups));
+ for (int i = 0; i < shortcutLabels.length; i++) {
+ final Icon icon = getIconForIntentCategory(intentCategories[i], userId);
+ if (icon != null) {
+ CharSequence label =
+ shortcutLabels[i];
+ KeyboardShortcutInfo keyboardShortcutInfo = new KeyboardShortcutInfo(
+ label,
+ icon,
+ keyCodes[i],
+ KeyEvent.META_META_ON);
+ List<ShortcutKeyGroup> shortcutKeyGroups =
+ Arrays.asList(new ShortcutKeyGroup(keyboardShortcutInfo, null));
+ shortcutMultiMappingInfos.add(
+ new ShortcutMultiMappingInfo(label, icon, shortcutKeyGroups));
+ }
}
}
@@ -1220,7 +1229,8 @@ public final class KeyboardShortcutListSearch {
String shortcutKeyString = null;
Drawable shortcutKeyDrawable = null;
if (info.getBaseCharacter() > Character.MIN_VALUE) {
- shortcutKeyString = String.valueOf(info.getBaseCharacter());
+ shortcutKeyString = String.valueOf(info.getBaseCharacter())
+ .toUpperCase(Locale.getDefault());
} else if (mSpecialCharacterNames.get(info.getKeycode()) != null) {
shortcutKeyString = mSpecialCharacterNames.get(info.getKeycode());
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
index 6ee13c3b1801..da89eea35f4c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
@@ -20,6 +20,7 @@ import static android.content.Context.LAYOUT_INFLATER_SERVICE;
import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_YES;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
+import static com.android.systemui.Flags.fetchBookmarksXmlKeyboardShortcuts;
import static com.android.systemui.Flags.validateKeyboardShortcutHelperIconUri;
import android.annotation.NonNull;
@@ -75,6 +76,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
+import java.util.Locale;
/**
* Contains functionality for handling keyboard shortcuts.
@@ -133,6 +135,7 @@ public final class KeyboardShortcuts {
@Nullable private List<KeyboardShortcutGroup> mReceivedAppShortcutGroups = null;
@Nullable private List<KeyboardShortcutGroup> mReceivedImeShortcutGroups = null;
+ @Nullable private KeyboardShortcutGroup mDefaultApplicationShortcuts = null;
@VisibleForTesting
KeyboardShortcuts(Context context, WindowManager windowManager) {
@@ -259,7 +262,8 @@ public final class KeyboardShortcuts {
context.getString(R.string.keyboard_key_button_template, "Mode"));
mSpecialCharacterNames.put(
KeyEvent.KEYCODE_FORWARD_DEL, context.getString(R.string.keyboard_key_forward_del));
- mSpecialCharacterNames.put(KeyEvent.KEYCODE_ESCAPE, "Esc");
+ mSpecialCharacterNames.put(
+ KeyEvent.KEYCODE_ESCAPE, context.getString(R.string.keyboard_key_esc));
mSpecialCharacterNames.put(KeyEvent.KEYCODE_SYSRQ, "SysRq");
mSpecialCharacterNames.put(KeyEvent.KEYCODE_BREAK, "Break");
mSpecialCharacterNames.put(KeyEvent.KEYCODE_SCROLL_LOCK, "Scroll Lock");
@@ -389,6 +393,7 @@ public final class KeyboardShortcuts {
mReceivedAppShortcutGroups = null;
mReceivedImeShortcutGroups = null;
+ mDefaultApplicationShortcuts = getDefaultApplicationShortcuts(deviceId);
mWindowManager.requestAppKeyboardShortcuts(
result -> {
mBackgroundHandler.post(() -> {
@@ -442,10 +447,8 @@ public final class KeyboardShortcuts {
mReceivedAppShortcutGroups = null;
mReceivedImeShortcutGroups = null;
- final KeyboardShortcutGroup defaultAppShortcuts =
- getDefaultApplicationShortcuts();
- if (defaultAppShortcuts != null) {
- shortcutGroups.add(defaultAppShortcuts);
+ if (mDefaultApplicationShortcuts != null) {
+ shortcutGroups.add(mDefaultApplicationShortcuts);
}
shortcutGroups.add(getSystemShortcuts());
showKeyboardShortcutsDialog(shortcutGroups);
@@ -498,7 +501,7 @@ public final class KeyboardShortcuts {
return systemGroup;
}
- private KeyboardShortcutGroup getDefaultApplicationShortcuts() {
+ private KeyboardShortcutGroup getDefaultApplicationShortcuts(int deviceId) {
final int userId = mContext.getUserId();
List<KeyboardShortcutInfo> keyboardShortcutInfoAppItems = new ArrayList<>();
@@ -528,65 +531,77 @@ public final class KeyboardShortcuts {
}
}
- // Browser.
- final Icon browserIcon = getIconForIntentCategory(Intent.CATEGORY_APP_BROWSER, userId);
- if (browserIcon != null) {
- keyboardShortcutInfoAppItems.add(new KeyboardShortcutInfo(
- mContext.getString(R.string.keyboard_shortcut_group_applications_browser),
- browserIcon,
- KeyEvent.KEYCODE_B,
- KeyEvent.META_META_ON));
- }
+ CharSequence categoryTitle;
+ if (fetchBookmarksXmlKeyboardShortcuts()) {
+ KeyboardShortcutGroup apps =
+ mWindowManager.getApplicationLaunchKeyboardShortcuts(deviceId);
+ categoryTitle = apps.getLabel();
+ keyboardShortcutInfoAppItems.addAll(apps.getItems());
+ } else {
+ categoryTitle = mContext.getString(R.string.keyboard_shortcut_group_applications);
+ // Browser.
+ final Icon browserIcon = getIconForIntentCategory(Intent.CATEGORY_APP_BROWSER, userId);
+ if (browserIcon != null) {
+ keyboardShortcutInfoAppItems.add(new KeyboardShortcutInfo(
+ mContext.getString(R.string.keyboard_shortcut_group_applications_browser),
+ browserIcon,
+ KeyEvent.KEYCODE_B,
+ KeyEvent.META_META_ON));
+ }
- // Contacts.
- final Icon contactsIcon = getIconForIntentCategory(Intent.CATEGORY_APP_CONTACTS, userId);
- if (contactsIcon != null) {
- keyboardShortcutInfoAppItems.add(new KeyboardShortcutInfo(
- mContext.getString(R.string.keyboard_shortcut_group_applications_contacts),
- contactsIcon,
- KeyEvent.KEYCODE_C,
- KeyEvent.META_META_ON));
- }
+ // Contacts.
+ final Icon contactsIcon = getIconForIntentCategory(
+ Intent.CATEGORY_APP_CONTACTS, userId);
+ if (contactsIcon != null) {
+ keyboardShortcutInfoAppItems.add(new KeyboardShortcutInfo(
+ mContext.getString(R.string.keyboard_shortcut_group_applications_contacts),
+ contactsIcon,
+ KeyEvent.KEYCODE_C,
+ KeyEvent.META_META_ON));
+ }
- // Email.
- final Icon emailIcon = getIconForIntentCategory(Intent.CATEGORY_APP_EMAIL, userId);
- if (emailIcon != null) {
- keyboardShortcutInfoAppItems.add(new KeyboardShortcutInfo(
- mContext.getString(R.string.keyboard_shortcut_group_applications_email),
- emailIcon,
- KeyEvent.KEYCODE_E,
- KeyEvent.META_META_ON));
- }
+ // Email.
+ final Icon emailIcon = getIconForIntentCategory(Intent.CATEGORY_APP_EMAIL, userId);
+ if (emailIcon != null) {
+ keyboardShortcutInfoAppItems.add(new KeyboardShortcutInfo(
+ mContext.getString(R.string.keyboard_shortcut_group_applications_email),
+ emailIcon,
+ KeyEvent.KEYCODE_E,
+ KeyEvent.META_META_ON));
+ }
- // Messaging.
- final Icon messagingIcon = getIconForIntentCategory(Intent.CATEGORY_APP_MESSAGING, userId);
- if (messagingIcon != null) {
- keyboardShortcutInfoAppItems.add(new KeyboardShortcutInfo(
- mContext.getString(R.string.keyboard_shortcut_group_applications_sms),
- messagingIcon,
- KeyEvent.KEYCODE_S,
- KeyEvent.META_META_ON));
- }
+ // Messaging.
+ final Icon messagingIcon = getIconForIntentCategory(
+ Intent.CATEGORY_APP_MESSAGING, userId);
+ if (messagingIcon != null) {
+ keyboardShortcutInfoAppItems.add(new KeyboardShortcutInfo(
+ mContext.getString(R.string.keyboard_shortcut_group_applications_sms),
+ messagingIcon,
+ KeyEvent.KEYCODE_S,
+ KeyEvent.META_META_ON));
+ }
- // Music.
- final Icon musicIcon = getIconForIntentCategory(Intent.CATEGORY_APP_MUSIC, userId);
- if (musicIcon != null) {
- keyboardShortcutInfoAppItems.add(new KeyboardShortcutInfo(
- mContext.getString(R.string.keyboard_shortcut_group_applications_music),
- musicIcon,
- KeyEvent.KEYCODE_P,
- KeyEvent.META_META_ON));
- }
+ // Music.
+ final Icon musicIcon = getIconForIntentCategory(Intent.CATEGORY_APP_MUSIC, userId);
+ if (musicIcon != null) {
+ keyboardShortcutInfoAppItems.add(new KeyboardShortcutInfo(
+ mContext.getString(R.string.keyboard_shortcut_group_applications_music),
+ musicIcon,
+ KeyEvent.KEYCODE_P,
+ KeyEvent.META_META_ON));
+ }
- // Calendar.
- final Icon calendarIcon = getIconForIntentCategory(Intent.CATEGORY_APP_CALENDAR, userId);
- if (calendarIcon != null) {
- keyboardShortcutInfoAppItems.add(new KeyboardShortcutInfo(
- mContext.getString(R.string.keyboard_shortcut_group_applications_calendar),
- calendarIcon,
- KeyEvent.KEYCODE_K,
- KeyEvent.META_META_ON));
+ // Calendar.
+ final Icon calendarIcon = getIconForIntentCategory(
+ Intent.CATEGORY_APP_CALENDAR, userId);
+ if (calendarIcon != null) {
+ keyboardShortcutInfoAppItems.add(new KeyboardShortcutInfo(
+ mContext.getString(R.string.keyboard_shortcut_group_applications_calendar),
+ calendarIcon,
+ KeyEvent.KEYCODE_K,
+ KeyEvent.META_META_ON));
+ }
}
final int itemsSize = keyboardShortcutInfoAppItems.size();
@@ -597,7 +612,7 @@ public final class KeyboardShortcuts {
// Sorts by label, case insensitive with nulls and/or empty labels last.
Collections.sort(keyboardShortcutInfoAppItems, mApplicationItemsComparator);
return new KeyboardShortcutGroup(
- mContext.getString(R.string.keyboard_shortcut_group_applications),
+ categoryTitle,
keyboardShortcutInfoAppItems,
true);
}
@@ -776,7 +791,8 @@ public final class KeyboardShortcuts {
String shortcutKeyString = null;
Drawable shortcutKeyDrawable = null;
if (info.getBaseCharacter() > Character.MIN_VALUE) {
- shortcutKeyString = String.valueOf(info.getBaseCharacter());
+ shortcutKeyString = String.valueOf(info.getBaseCharacter())
+ .toUpperCase(Locale.getDefault());
} else if (mSpecialCharacterNames.get(info.getKeycode()) != null) {
shortcutKeyString = mSpecialCharacterNames.get(info.getKeycode());
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
index e505ef753dce..0957e5a5df35 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
@@ -51,6 +51,7 @@ import com.android.systemui.deviceentry.shared.model.DeviceUnlockStatus;
import com.android.systemui.keyguard.MigrateClocksToBlueprint;
import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
+import com.android.systemui.keyguard.shared.model.KeyguardState;
import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
import com.android.systemui.res.R;
import com.android.systemui.scene.domain.interactor.SceneContainerOcclusionInteractor;
@@ -223,6 +224,10 @@ public class StatusBarStateControllerImpl implements
mSceneContainerOcclusionInteractorLazy.get().getInvisibleDueToOcclusion(),
this::calculateStateFromSceneFramework),
this::onStatusBarStateChanged);
+
+ mJavaAdapter.alwaysCollectFlow(
+ mKeyguardTransitionInteractorLazy.get().transitionValue(KeyguardState.AOD),
+ this::onAodKeyguardStateTransitionValueChanged);
}
}
@@ -693,6 +698,14 @@ public class StatusBarStateControllerImpl implements
updateStateAndNotifyListeners(newState);
}
+ private void onAodKeyguardStateTransitionValueChanged(float value) {
+ if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) {
+ return;
+ }
+
+ setDozeAmountInternal(value);
+ }
+
private static final Map<SceneKey, Integer> sStatusBarStateByLockedSceneKey = Map.of(
Scenes.Lockscreen, StatusBarState.KEYGUARD,
Scenes.Bouncer, StatusBarState.KEYGUARD,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/domain/interactor/StatusBarKeyguardViewManagerInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/domain/interactor/StatusBarKeyguardViewManagerInteractor.kt
index ef96f43ec17e..9ca110e8c561 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/domain/interactor/StatusBarKeyguardViewManagerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/domain/interactor/StatusBarKeyguardViewManagerInteractor.kt
@@ -93,8 +93,8 @@ constructor(
private val occlusionStateFromFinishedStep =
combine(
keyguardTransitionInteractor.isFinishedIn(
- Scenes.Gone,
- stateWithoutSceneContainer = KeyguardState.GONE
+ scene = Scenes.Gone,
+ stateWithoutSceneContainer = KeyguardState.GONE,
),
keyguardTransitionInteractor.isFinishedIn(KeyguardState.OCCLUDED),
keyguardOcclusionInteractor.isShowWhenLockedActivityOnTop,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
index f98a88f5328b..e48c28d3f3ee 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
@@ -698,7 +698,7 @@ public final class NotificationEntry extends ListEntry implements NotificationRo
}
public void setHeadsUpIsVisible() {
- if (row != null) row.setHeadsUpIsVisible();
+ if (row != null) row.markHeadsUpSeen();
}
//TODO: i'm imagining a world where this isn't just the row, but I could be rwong
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt
index 1434dc034881..55c6790d4fb1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt
@@ -125,7 +125,10 @@ constructor(
// Whether or not keyguard is visible (or occluded).
val isKeyguardPresent: Flow<Boolean> =
keyguardTransitionInteractor
- .transitionValue(Scenes.Gone, stateWithoutSceneContainer = KeyguardState.GONE)
+ .transitionValue(
+ scene = Scenes.Gone,
+ stateWithoutSceneContainer = KeyguardState.GONE,
+ )
.map { it == 0f }
.distinctUntilChanged()
.onEach { trackingUnseen -> logger.logTrackingUnseen(trackingUnseen) }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/VisualStabilityProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/VisualStabilityProvider.kt
index f166d32812ae..5adf31b75fa7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/VisualStabilityProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/VisualStabilityProvider.kt
@@ -13,18 +13,12 @@ class VisualStabilityProvider @Inject constructor() {
/** The subset of active listeners which are temporary (will be removed after called) */
private val temporaryListeners = ArraySet<OnReorderingAllowedListener>()
- private val banListeners = ListenerSet<OnReorderingBannedListener>()
-
var isReorderingAllowed = true
set(value) {
if (field != value) {
field = value
if (value) {
notifyReorderingAllowed()
- } else {
- banListeners.forEach { listener ->
- listener.onReorderingBanned()
- }
}
}
}
@@ -44,10 +38,6 @@ class VisualStabilityProvider @Inject constructor() {
allListeners.addIfAbsent(listener)
}
- fun addPersistentReorderingBannedListener(listener: OnReorderingBannedListener) {
- banListeners.addIfAbsent(listener)
- }
-
/** Add a listener which will be removed when it is called. */
fun addTemporaryReorderingAllowedListener(listener: OnReorderingAllowedListener) {
// Only add to the temporary set if it was added to the global set
@@ -67,8 +57,3 @@ class VisualStabilityProvider @Inject constructor() {
fun interface OnReorderingAllowedListener {
fun onReorderingAllowed()
}
-
-fun interface OnReorderingBannedListener {
- fun onReorderingBanned()
-}
-
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationInteractor.kt
index eebbb13005b9..bf44b9f3cf78 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationInteractor.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-@file:OptIn(ExperimentalCoroutinesApi::class, FlowPreview::class)
+@file:OptIn(ExperimentalCoroutinesApi::class)
package com.android.systemui.statusbar.notification.domain.interactor
@@ -25,17 +25,14 @@ import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.statusbar.notification.data.repository.HeadsUpRepository
import com.android.systemui.statusbar.notification.data.repository.HeadsUpRowRepository
import com.android.systemui.statusbar.notification.shared.HeadsUpRowKey
+import com.android.systemui.statusbar.notification.shared.NotificationsHeadsUpRefactor
import javax.inject.Inject
import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
-import kotlinx.coroutines.flow.debounce
-import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.flow.onStart
class HeadsUpNotificationInteractor
@Inject
@@ -50,48 +47,54 @@ constructor(
val topHeadsUpRow: Flow<HeadsUpRowKey?> = headsUpRepository.topHeadsUpRow
/** Set of currently pinned top-level heads up rows to be displayed. */
- val pinnedHeadsUpRows: Flow<Set<HeadsUpRowKey>> =
- headsUpRepository.activeHeadsUpRows.flatMapLatest { repositories ->
- if (repositories.isNotEmpty()) {
- val toCombine: List<Flow<Pair<HeadsUpRowRepository, Boolean>>> =
- repositories.map { repo -> repo.isPinned.map { isPinned -> repo to isPinned } }
- combine(toCombine) { pairs ->
- pairs.filter { (_, isPinned) -> isPinned }.map { (repo, _) -> repo }.toSet()
+ val pinnedHeadsUpRows: Flow<Set<HeadsUpRowKey>> by lazy {
+ if (NotificationsHeadsUpRefactor.isUnexpectedlyInLegacyMode()) {
+ flowOf(emptySet())
+ } else {
+ headsUpRepository.activeHeadsUpRows.flatMapLatest { repositories ->
+ if (repositories.isNotEmpty()) {
+ val toCombine: List<Flow<Pair<HeadsUpRowRepository, Boolean>>> =
+ repositories.map { repo ->
+ repo.isPinned.map { isPinned -> repo to isPinned }
+ }
+ combine(toCombine) { pairs ->
+ pairs.filter { (_, isPinned) -> isPinned }.map { (repo, _) -> repo }.toSet()
+ }
+ } else {
+ // if the set is empty, there are no flows to combine
+ flowOf(emptySet())
}
- } else {
- // if the set is empty, there are no flows to combine
- flowOf(emptySet())
}
}
+ }
/** Are there any pinned heads up rows to display? */
- val hasPinnedRows: Flow<Boolean> =
- headsUpRepository.activeHeadsUpRows.flatMapLatest { rows ->
- if (rows.isNotEmpty()) {
- combine(rows.map { it.isPinned }) { pins -> pins.any { it } }
- } else {
- // if the set is empty, there are no flows to combine
- flowOf(false)
+ val hasPinnedRows: Flow<Boolean> by lazy {
+ if (NotificationsHeadsUpRefactor.isUnexpectedlyInLegacyMode()) {
+ flowOf(false)
+ } else {
+ headsUpRepository.activeHeadsUpRows.flatMapLatest { rows ->
+ if (rows.isNotEmpty()) {
+ combine(rows.map { it.isPinned }) { pins -> pins.any { it } }
+ } else {
+ // if the set is empty, there are no flows to combine
+ flowOf(false)
+ }
}
}
+ }
- val isHeadsUpOrAnimatingAway: Flow<Boolean> =
- combine(hasPinnedRows, headsUpRepository.isHeadsUpAnimatingAway) {
- hasPinnedRows,
- animatingAway ->
- hasPinnedRows || animatingAway
- }
- .debounce { isHeadsUpOrAnimatingAway ->
- if (isHeadsUpOrAnimatingAway) {
- 0
- } else {
- // When the last pinned entry is removed from the [HeadsUpRepository],
- // there might be a delay before the View starts animating.
- 50L
+ val isHeadsUpOrAnimatingAway: Flow<Boolean> by lazy {
+ if (NotificationsHeadsUpRefactor.isUnexpectedlyInLegacyMode()) {
+ flowOf(false)
+ } else {
+ combine(hasPinnedRows, headsUpRepository.isHeadsUpAnimatingAway) {
+ hasPinnedRows,
+ animatingAway ->
+ hasPinnedRows || animatingAway
}
- }
- .onStart { emit(false) } // emit false, so we don't wait for the initial update
- .distinctUntilChanged()
+ }
+ }
private val canShowHeadsUp: Flow<Boolean> =
combine(
@@ -109,10 +112,15 @@ constructor(
}
}
- val showHeadsUpStatusBar: Flow<Boolean> =
- combine(hasPinnedRows, canShowHeadsUp) { hasPinnedRows, canShowHeadsUp ->
- hasPinnedRows && canShowHeadsUp
+ val showHeadsUpStatusBar: Flow<Boolean> by lazy {
+ if (NotificationsHeadsUpRefactor.isUnexpectedlyInLegacyMode()) {
+ flowOf(false)
+ } else {
+ combine(hasPinnedRows, canShowHeadsUp) { hasPinnedRows, canShowHeadsUp ->
+ hasPinnedRows && canShowHeadsUp
+ }
}
+ }
fun headsUpRow(key: HeadsUpRowKey): HeadsUpRowInteractor =
HeadsUpRowInteractor(key as HeadsUpRowRepository)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 9e943ee597f3..1cbb16e3983a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -371,12 +371,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
setUserExpanded(nowExpanded);
}
- if (ExpandHeadsUpOnInlineReply.isEnabled() && mExpandable) {
- // it is triggered by the user.
- // So, mHasUserChangedExpansion should be marked true.
- mHasUserChangedExpansion = true;
- }
-
notifyHeightChanged(/* needsAnimation= */ true);
mOnExpandClickListener.onExpandClicked(mEntry, v, nowExpanded);
if (shouldLogExpandClickMetric) {
@@ -865,8 +859,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
@Override
- public void setHeadsUpIsVisible() {
- super.setHeadsUpIsVisible();
+ public void markHeadsUpSeen() {
+ super.markHeadsUpSeen();
mMustStayOnScreen = false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
index 2af119f98f4a..6becbd295264 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
@@ -637,7 +637,10 @@ public abstract class ExpandableView extends FrameLayout implements Dumpable, Ro
return false;
}
- public void setHeadsUpIsVisible() {
+ /**
+ * Called, when the notification has been seen by the user in the heads up state.
+ */
+ public void markHeadsUpSeen() {
}
public boolean showingPulsing() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RichOngoingNotificationContentExtractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RichOngoingNotificationContentExtractor.kt
index b5ea861c19a6..b8af3698fb63 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RichOngoingNotificationContentExtractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RichOngoingNotificationContentExtractor.kt
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.notification.row
import android.app.Notification
+import android.app.Notification.RichOngoingStyle
import android.app.PendingIntent
import android.content.Context
import android.util.Log
@@ -68,12 +69,14 @@ class RichOngoingNotificationContentExtractorImpl @Inject constructor() :
builder: Notification.Builder,
systemUIContext: Context,
packageContext: Context
- ): RichOngoingContentModel? =
+ ): RichOngoingContentModel? {
+ if (builder.style !is RichOngoingStyle) return null
+
try {
val sbn = entry.sbn
val notification = sbn.notification
val icon = IconModel(notification.smallIcon)
- if (sbn.packageName == "com.google.android.deskclock") {
+ return if (sbn.packageName == "com.google.android.deskclock") {
when (notification.channelId) {
"Timers v2" -> {
parseTimerNotification(notification, icon)
@@ -90,8 +93,9 @@ class RichOngoingNotificationContentExtractorImpl @Inject constructor() :
} else null
} catch (e: Exception) {
Log.e("RONs", "Error parsing RON", e)
- null
+ return null
}
+ }
/**
* FOR PROTOTYPING ONLY: create a RON TimerContentModel using the time information available
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ExpandableViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ExpandableViewState.java
index d1e5ab04a630..83de2265b98e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ExpandableViewState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ExpandableViewState.java
@@ -176,7 +176,7 @@ public class ExpandableViewState extends ViewState {
expandableView.setInShelf(inShelf);
if (headsUpIsVisible) {
- expandableView.setHeadsUpIsVisible();
+ expandableView.markHeadsUpSeen();
}
}
}
@@ -231,7 +231,7 @@ public class ExpandableViewState extends ViewState {
expandableView.setInShelf(this.inShelf);
if (headsUpIsVisible) {
- expandableView.setHeadsUpIsVisible();
+ expandableView.markHeadsUpSeen();
}
}
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 dab379930105..1789ad6a7216 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
@@ -715,6 +715,7 @@ public class NotificationStackScrollLayout
}
public float getNotificationSquishinessFraction() {
+ SceneContainerFlag.assertInLegacyMode();
return mStackScrollAlgorithm.getNotificationSquishinessFraction(mAmbientState);
}
@@ -860,7 +861,7 @@ public class NotificationStackScrollLayout
/* label= */ "getHeight() - mKeyguardBottomPadding = " + y);
}
- y = getHeight() - getEmptyBottomMargin();
+ y = getHeight() - getEmptyBottomMarginInternal();
drawDebugInfo(canvas, y, Color.GREEN,
/* label= */ "getHeight() - getEmptyBottomMargin() = " + y);
@@ -1270,7 +1271,7 @@ public class NotificationStackScrollLayout
private void updateAlgorithmLayoutMinHeight() {
mAmbientState.setLayoutMinHeight(mQsFullScreen || isHeadsUpTransition()
- ? getLayoutMinHeight() : 0);
+ ? getLayoutMinHeightInternal() : 0);
}
/**
@@ -1444,7 +1445,7 @@ public class NotificationStackScrollLayout
} else {
if (mQsExpansionFraction <= 0 && !shouldSkipHeightUpdate()) {
final float endHeight = updateStackEndHeight(
- getHeight(), getEmptyBottomMargin(), getTopPadding());
+ getHeight(), getEmptyBottomMarginInternal(), getTopPadding());
updateStackHeight(endHeight, fraction);
} else {
// Always updateStackHeight to prevent jumps in the stack height when this fraction
@@ -1617,7 +1618,7 @@ public class NotificationStackScrollLayout
float appear;
float expandAmount;
if (mKeyguardBypassEnabled && onKeyguard()) {
- appear = calculateAppearFractionBypass();
+ appear = calculateAppearFractionBypassInternal();
expandAmount = getPulseHeight();
} else {
appear = MathUtils.saturate(calculateAppearFraction(mExpandedHeight));
@@ -1642,6 +1643,7 @@ public class NotificationStackScrollLayout
* Return the height of the content ignoring the footer.
*/
public int getIntrinsicContentHeight() {
+ SceneContainerFlag.assertInLegacyMode();
return (int) mIntrinsicContentHeight;
}
@@ -2373,6 +2375,11 @@ public class NotificationStackScrollLayout
* @return the first child which has visibility unequal to GONE
*/
public ExpandableView getFirstChildNotGone() {
+ SceneContainerFlag.assertInLegacyMode();
+ return getFirstChildNotGoneInternal();
+ }
+
+ private ExpandableView getFirstChildNotGoneInternal() {
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
@@ -2432,6 +2439,7 @@ public class NotificationStackScrollLayout
* @return the number of children which have visibility unequal to GONE
*/
public int getNotGoneChildCount() {
+ SceneContainerFlag.assertInLegacyMode();
int childCount = getChildCount();
int count = 0;
for (int i = 0; i < childCount; i++) {
@@ -2642,7 +2650,7 @@ public class NotificationStackScrollLayout
*/
public void updateTopPadding(float qsHeight, boolean animate) {
int topPadding = (int) qsHeight;
- int minStackHeight = getLayoutMinHeight();
+ int minStackHeight = getLayoutMinHeightInternal();
if (topPadding + minStackHeight > getHeight()) {
mTopPaddingOverflow = topPadding + minStackHeight - getHeight();
} else {
@@ -2658,6 +2666,11 @@ public class NotificationStackScrollLayout
}
public int getLayoutMinHeight() {
+ SceneContainerFlag.assertInLegacyMode();
+ return getLayoutMinHeightInternal();
+ }
+
+ private int getLayoutMinHeightInternal() {
if (isHeadsUpTransition()) {
ExpandableNotificationRow trackedHeadsUpRow = mAmbientState.getTrackedHeadsUpRow();
if (trackedHeadsUpRow.isAboveShelf()) {
@@ -3430,7 +3443,7 @@ public class NotificationStackScrollLayout
* @return Whether a y coordinate is inside the content.
*/
public boolean isInContentBounds(float y) {
- return y < getHeight() - getEmptyBottomMargin();
+ return y < getHeight() - getEmptyBottomMarginInternal();
}
private float getTouchSlop(MotionEvent event) {
@@ -4063,10 +4076,16 @@ public class NotificationStackScrollLayout
}
boolean isScrolledToBottom() {
+ SceneContainerFlag.assertInLegacyMode();
return mScrollAdapter.isScrolledToBottom();
}
int getEmptyBottomMargin() {
+ SceneContainerFlag.assertInLegacyMode();
+ return getEmptyBottomMarginInternal();
+ }
+
+ private int getEmptyBottomMarginInternal() {
int contentHeight;
if (mShouldUseSplitNotificationShade) {
// When in split shade and there are no notifications, the height can be too low, as
@@ -4249,7 +4268,7 @@ public class NotificationStackScrollLayout
private void updateScrollPositionOnExpandInBottom(ExpandableView view) {
if (view instanceof ExpandableNotificationRow row && !onKeyguard()) {
// TODO: once we're recycling this will need to check the adapter position of the child
- if (row.isUserLocked() && row != getFirstChildNotGone()) {
+ if (row.isUserLocked() && row != getFirstChildNotGoneInternal()) {
if (row.isSummaryWithChildren()) {
return;
}
@@ -4536,7 +4555,7 @@ public class NotificationStackScrollLayout
// clipped when pulsing
float ownTranslationZ = 0;
if (mKeyguardBypassEnabled && mAmbientState.isHiddenAtAll()) {
- ExpandableView firstChildNotGone = getFirstChildNotGone();
+ ExpandableView firstChildNotGone = getFirstChildNotGoneInternal();
if (firstChildNotGone != null && firstChildNotGone.showingPulsing()) {
ownTranslationZ = firstChildNotGone.getTranslationZ();
}
@@ -4684,10 +4703,12 @@ public class NotificationStackScrollLayout
}
public int getEmptyShadeViewHeight() {
+ SceneContainerFlag.assertInLegacyMode();
return mEmptyShadeView.getHeight();
}
public float getBottomMostNotificationBottom() {
+ SceneContainerFlag.assertInLegacyMode();
final int count = getChildCount();
float max = 0;
for (int childIdx = 0; childIdx < count; childIdx++) {
@@ -5110,6 +5131,7 @@ public class NotificationStackScrollLayout
}
public float getOpeningHeight() {
+ SceneContainerFlag.assertInLegacyMode();
if (mEmptyShadeView.getVisibility() == GONE) {
return getMinExpansionHeight();
} else {
@@ -5566,6 +5588,11 @@ public class NotificationStackScrollLayout
}
public float calculateAppearFractionBypass() {
+ SceneContainerFlag.assertInLegacyMode();
+ return calculateAppearFractionBypassInternal();
+ }
+
+ private float calculateAppearFractionBypassInternal() {
float pulseHeight = getPulseHeight();
// The total distance required to fully reveal the header
float totalDistance = getIntrinsicPadding();
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 36930bf0d528..726fdee79ef8 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
@@ -1004,6 +1004,7 @@ public class NotificationStackScrollLayoutController implements Dumpable {
}
public int getRight() {
+ SceneContainerFlag.assertInLegacyMode();
return mView.getRight();
}
@@ -1015,6 +1016,7 @@ public class NotificationStackScrollLayoutController implements Dumpable {
* @return the left of the view.
*/
public int getLeft() {
+ SceneContainerFlag.assertInLegacyMode();
return mView.getLeft();
}
@@ -1022,6 +1024,7 @@ public class NotificationStackScrollLayoutController implements Dumpable {
* @return the top of the view.
*/
public int getTop() {
+ SceneContainerFlag.assertInLegacyMode();
return mView.getTop();
}
@@ -1029,6 +1032,7 @@ public class NotificationStackScrollLayoutController implements Dumpable {
* @return the bottom of the view.
*/
public int getBottom() {
+ SceneContainerFlag.assertInLegacyMode();
return mView.getBottom();
}
@@ -1158,6 +1162,7 @@ public class NotificationStackScrollLayoutController implements Dumpable {
}
public int getIntrinsicContentHeight() {
+ SceneContainerFlag.assertInLegacyMode();
return mView.getIntrinsicContentHeight();
}
@@ -1216,6 +1221,7 @@ public class NotificationStackScrollLayoutController implements Dumpable {
}
public float getX() {
+ SceneContainerFlag.assertInLegacyMode();
return mView.getX();
}
@@ -1224,14 +1230,17 @@ public class NotificationStackScrollLayoutController implements Dumpable {
}
public float getWidth() {
+ SceneContainerFlag.assertInLegacyMode();
return mView.getWidth();
}
public float getOpeningHeight() {
+ SceneContainerFlag.assertInLegacyMode();
return mView.getOpeningHeight();
}
public float getBottomMostNotificationBottom() {
+ SceneContainerFlag.assertInLegacyMode();
return mView.getBottomMostNotificationBottom();
}
@@ -1266,10 +1275,12 @@ public class NotificationStackScrollLayoutController implements Dumpable {
}
public float getNotificationSquishinessFraction() {
+ SceneContainerFlag.assertInLegacyMode();
return mView.getNotificationSquishinessFraction();
}
public float calculateAppearFractionBypass() {
+ SceneContainerFlag.assertInLegacyMode();
return mView.calculateAppearFractionBypass();
}
@@ -1279,22 +1290,27 @@ public class NotificationStackScrollLayoutController implements Dumpable {
}
public boolean isScrolledToBottom() {
+ SceneContainerFlag.assertInLegacyMode();
return mView.isScrolledToBottom();
}
public int getNotGoneChildCount() {
+ SceneContainerFlag.assertInLegacyMode();
return mView.getNotGoneChildCount();
}
public float getIntrinsicPadding() {
+ SceneContainerFlag.assertInLegacyMode();
return mView.getIntrinsicPadding();
}
public float getLayoutMinHeight() {
+ SceneContainerFlag.assertInLegacyMode();
return mView.getLayoutMinHeight();
}
public int getEmptyBottomMargin() {
+ SceneContainerFlag.assertInLegacyMode();
return mView.getEmptyBottomMargin();
}
@@ -1307,6 +1323,7 @@ public class NotificationStackScrollLayoutController implements Dumpable {
}
public float getEmptyShadeViewHeight() {
+ SceneContainerFlag.assertInLegacyMode();
return mView.getEmptyShadeViewHeight();
}
@@ -1474,6 +1491,7 @@ public class NotificationStackScrollLayoutController implements Dumpable {
}
public boolean isShowingEmptyShadeView() {
+ SceneContainerFlag.assertInLegacyMode();
return mView.isEmptyShadeViewVisible();
}
@@ -1602,6 +1620,7 @@ public class NotificationStackScrollLayoutController implements Dumpable {
}
public ExpandableView getFirstChildNotGone() {
+ SceneContainerFlag.assertInLegacyMode();
return mView.getFirstChildNotGone();
}
@@ -1713,6 +1732,7 @@ public class NotificationStackScrollLayoutController implements Dumpable {
}
public boolean isLongPressInProgress() {
+ SceneContainerFlag.assertInLegacyMode();
return mLongPressedView != null;
}
@@ -1722,6 +1742,7 @@ public class NotificationStackScrollLayoutController implements Dumpable {
* from the keyguard host to the quick settings one.
*/
public int getFullShadeTransitionInset() {
+ SceneContainerFlag.assertInLegacyMode();
MediaContainerView view = mKeyguardMediaController.getSinglePaneContainer();
if (view == null || view.getHeight() == 0
|| mStatusBarStateController.getState() != KEYGUARD) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt
index 497ffcab32f2..6881d11bc95f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt
@@ -38,12 +38,14 @@ import com.android.systemui.util.kotlin.DisposableHandles
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.DisposableHandle
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
/** Binds the shared notification container to its view-model. */
+@OptIn(ExperimentalCoroutinesApi::class)
@SysUISingleton
class SharedNotificationContainerBinder
@Inject
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 900201f54bd7..d1d5d308f741 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
@@ -141,6 +141,7 @@ constructor(
private val communalSceneInteractor: CommunalSceneInteractor,
unfoldTransitionInteractor: UnfoldTransitionInteractor,
) : FlowDumperImpl(dumpManager) {
+ // TODO(b/349784682): Transform deprecated states for Flexiglass
private val statesForConstrainedNotifications: Set<KeyguardState> =
setOf(AOD, LOCKSCREEN, DOZING, ALTERNATE_BOUNCER, PRIMARY_BOUNCER)
private val statesForHiddenKeyguard: Set<KeyguardState> = setOf(GONE, OCCLUDED)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ui/viewbinder/HeadsUpNotificationViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ui/viewbinder/HeadsUpNotificationViewBinder.kt
index 52cb48be041f..8d73983e4053 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ui/viewbinder/HeadsUpNotificationViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ui/viewbinder/HeadsUpNotificationViewBinder.kt
@@ -51,8 +51,8 @@ constructor(private val viewModel: NotificationListViewModel) {
}
removed.forEach { key ->
val row = obtainView(key)
- parentView.generateHeadsUpAnimation(row, /* isHeadsUp = */ false)
- row.setHeadsUpIsVisible()
+ parentView.generateHeadsUpAnimation(row, /* isHeadsUp= */ false)
+ row.markHeadsUpSeen()
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
index 91b5d0be6f04..a5388564d5fd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
@@ -414,6 +414,14 @@ public class AutoTileManager implements UserAwareController {
}
}
+ @Override
+ public void onFeatureEnabledChanged(boolean enabled) {
+ if (!enabled) {
+ mHost.removeTile(BRIGHTNESS);
+ mHandler.post(() -> mReduceBrightColorsController.removeCallback(this));
+ }
+ }
+
private void addReduceBrightColorsTile() {
if (mAutoTracker.isAdded(BRIGHTNESS)) return;
mHost.addTile(BRIGHTNESS);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index 97b6f95ef3c4..6d76200de34e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -53,11 +53,14 @@ import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.keyguard.domain.interactor.BiometricUnlockInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
import com.android.systemui.keyguard.shared.model.BiometricUnlockSource;
+import com.android.systemui.keyguard.shared.model.Edge;
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.log.SessionTracker;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.res.R;
+import com.android.systemui.scene.shared.model.Scenes;
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.VibratorHelper;
@@ -327,14 +330,17 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
mSelectedUserInteractor = selectedUserInteractor;
mKeyguardTransitionInteractor = keyguardTransitionInteractor;
javaAdapter.alwaysCollectFlow(
- keyguardTransitionInteractor.getStartedKeyguardTransitionStep(),
- this::consumeTransitionStepOnStartedKeyguardState);
+ keyguardTransitionInteractor.transition(
+ /* edge */ Edge.create(Scenes.Gone, null),
+ /* edgeWithoutSceneContainer */ Edge.create(
+ KeyguardState.GONE, (KeyguardState) null)),
+ this::consumeFromGoneTransitions);
dumpManager.registerDumpable(this);
}
@VisibleForTesting
- protected void consumeTransitionStepOnStartedKeyguardState(TransitionStep transitionStep) {
- if (transitionStep.getFrom() == KeyguardState.GONE) {
+ protected void consumeFromGoneTransitions(TransitionStep transitionStep) {
+ if (transitionStep.getTransitionState() == TransitionState.STARTED) {
mBiometricUnlockInteractor.setBiometricUnlockState(MODE_NONE, null);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DarkIconDispatcherImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DarkIconDispatcherImpl.java
index bd0097e8fc3f..398c1d43d4fc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DarkIconDispatcherImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DarkIconDispatcherImpl.java
@@ -74,9 +74,9 @@ public class DarkIconDispatcherImpl implements SysuiDarkIconDispatcher,
mLightModeIconColorSingleTone = Color.WHITE;
} else {
mDarkModeIconColorSingleTone = context.getColor(
- com.android.settingslib.R.color.black);
+ com.android.settingslib.R.color.dark_mode_icon_color_single_tone);
mLightModeIconColorSingleTone = context.getColor(
- com.android.settingslib.R.color.white);
+ com.android.settingslib.R.color.light_mode_icon_color_single_tone);
}
mTransitionsController = lightBarTransitionsControllerFactory.create(this);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
index a11cbc3bf231..98869bef5bf0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
@@ -37,6 +37,7 @@ import androidx.annotation.VisibleForTesting;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.Dumpable;
+import com.android.systemui.Flags;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
@@ -54,6 +55,7 @@ import com.android.systemui.statusbar.policy.DevicePostureController;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.unfold.FoldAodAnimationController;
import com.android.systemui.unfold.SysUIUnfoldComponent;
+import com.android.systemui.util.settings.SecureSettings;
import java.io.PrintWriter;
import java.util.Optional;
@@ -86,6 +88,7 @@ public class DozeParameters implements
private final FoldAodAnimationController mFoldAodAnimationController;
private final UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
private final UserTracker mUserTracker;
+ private final SecureSettings mSecureSettings;
private boolean mDozeAlwaysOn;
private boolean mControlScreenOffAnimation;
@@ -130,7 +133,8 @@ public class DozeParameters implements
ConfigurationController configurationController,
StatusBarStateController statusBarStateController,
UserTracker userTracker,
- DozeInteractor dozeInteractor) {
+ DozeInteractor dozeInteractor,
+ SecureSettings secureSettings) {
mResources = resources;
mAmbientDisplayConfiguration = ambientDisplayConfiguration;
mAlwaysOnPolicy = alwaysOnDisplayPolicy;
@@ -144,6 +148,7 @@ public class DozeParameters implements
mUnlockedScreenOffAnimationController = unlockedScreenOffAnimationController;
mUserTracker = userTracker;
mDozeInteractor = dozeInteractor;
+ mSecureSettings = secureSettings;
keyguardUpdateMonitor.registerCallback(mKeyguardVisibilityCallback);
tunerService.addTunable(
@@ -160,7 +165,8 @@ public class DozeParameters implements
mFoldAodAnimationController.addCallback(this);
}
- SettingsObserver quickPickupSettingsObserver = new SettingsObserver(context, handler);
+ SettingsObserver quickPickupSettingsObserver =
+ new SettingsObserver(context, handler, mSecureSettings);
quickPickupSettingsObserver.observe();
batteryController.addCallback(new BatteryStateChangeCallback() {
@@ -479,18 +485,36 @@ public class DozeParameters implements
Settings.Secure.getUriFor(Settings.Secure.DOZE_ALWAYS_ON);
private final Context mContext;
- SettingsObserver(Context context, Handler handler) {
+ private final Handler mHandler;
+ private final SecureSettings mSecureSettings;
+
+ SettingsObserver(Context context, Handler handler, SecureSettings secureSettings) {
super(handler);
mContext = context;
+ mHandler = handler;
+ mSecureSettings = secureSettings;
}
void observe() {
- ContentResolver resolver = mContext.getContentResolver();
- resolver.registerContentObserver(mQuickPickupGesture, false, this,
- UserHandle.USER_ALL);
- resolver.registerContentObserver(mPickupGesture, false, this, UserHandle.USER_ALL);
- resolver.registerContentObserver(mAlwaysOnEnabled, false, this, UserHandle.USER_ALL);
- update(null);
+ if (Flags.registerContentObserversAsync()) {
+ mSecureSettings.registerContentObserverForUserAsync(mQuickPickupGesture,
+ this, UserHandle.USER_ALL);
+ mSecureSettings.registerContentObserverForUserAsync(mPickupGesture,
+ this, UserHandle.USER_ALL);
+ mSecureSettings.registerContentObserverForUserAsync(mAlwaysOnEnabled,
+ this, UserHandle.USER_ALL,
+ // The register calls are called in order, so this ensures that update()
+ // is called after them all and value retrieval isn't racy.
+ () -> mHandler.post(() -> update(null)));
+ } else {
+ ContentResolver resolver = mContext.getContentResolver();
+ resolver.registerContentObserver(mQuickPickupGesture, false, this,
+ UserHandle.USER_ALL);
+ resolver.registerContentObserver(mPickupGesture, false, this, UserHandle.USER_ALL);
+ resolver.registerContentObserver(mAlwaysOnEnabled, false, this,
+ UserHandle.USER_ALL);
+ update(null);
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
index 330383ff03af..a32d5fef58eb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
@@ -29,8 +29,10 @@ import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
+import androidx.annotation.MainThread;
import androidx.annotation.Nullable;
+import com.android.app.tracing.TraceUtils;
import com.android.internal.annotations.VisibleForTesting;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.assist.AssistManager;
@@ -61,6 +63,8 @@ import com.android.systemui.util.IListenerSet;
import dagger.Lazy;
+import kotlin.Unit;
+
import kotlinx.coroutines.ExperimentalCoroutinesApi;
import javax.inject.Inject;
@@ -109,7 +113,7 @@ public final class DozeServiceHost implements DozeHost {
private CentralSurfaces mCentralSurfaces;
private boolean mAlwaysOnSuppressed;
private boolean mPulsePending;
- private DozeInteractor mDozeInteractor;
+ private final DozeInteractor mDozeInteractor;
@Inject
public DozeServiceHost(DozeLog dozeLog, PowerManager powerManager,
@@ -337,13 +341,17 @@ public final class DozeServiceHost implements DozeHost {
}
@Override
+ @MainThread
public void dozeTimeTick() {
- mDozeInteractor.dozeTimeTick();
- mShadeLockscreenInteractor.dozeTimeTick();
- mAuthController.dozeTimeTick();
- if (mAmbientIndicationContainer instanceof DozeReceiver) {
- ((DozeReceiver) mAmbientIndicationContainer).dozeTimeTick();
- }
+ TraceUtils.trace("DozeServiceHost#dozeTimeTick", () -> {
+ mDozeInteractor.dozeTimeTick();
+ mShadeLockscreenInteractor.dozeTimeTick();
+ mAuthController.dozeTimeTick();
+ if (mAmbientIndicationContainer instanceof DozeReceiver) {
+ ((DozeReceiver) mAmbientIndicationContainer).dozeTimeTick();
+ }
+ return Unit.INSTANCE;
+ });
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
index 0623bb2c274a..a2e44dffb767 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
@@ -31,7 +31,6 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.policy.SystemBarUtils;
import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
@@ -40,7 +39,6 @@ import com.android.systemui.shade.domain.interactor.ShadeInteractor;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.provider.OnReorderingAllowedListener;
-import com.android.systemui.statusbar.notification.collection.provider.OnReorderingBannedListener;
import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider;
import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
import com.android.systemui.statusbar.notification.data.repository.HeadsUpRepository;
@@ -88,7 +86,7 @@ public class HeadsUpManagerPhone extends BaseHeadsUpManager implements
private final List<OnHeadsUpPhoneListenerChange> mHeadsUpPhoneListeners = new ArrayList<>();
private final VisualStabilityProvider mVisualStabilityProvider;
- private AvalancheController mAvalancheController;
+ private final AvalancheController mAvalancheController;
// TODO(b/328393698) move the topHeadsUpRow logic to an interactor
private final MutableStateFlow<HeadsUpRowRepository> mTopHeadsUpRow =
@@ -173,11 +171,8 @@ public class HeadsUpManagerPhone extends BaseHeadsUpManager implements
updateResources();
}
});
- if (!NotificationsHeadsUpRefactor.isEnabled()) {
- javaAdapter.alwaysCollectFlow(shadeInteractor.isAnyExpanded(),
+ javaAdapter.alwaysCollectFlow(shadeInteractor.isAnyExpanded(),
this::onShadeOrQsExpanded);
- }
- mVisualStabilityProvider.addPersistentReorderingBannedListener(mOnReorderingBannedListener);
}
public void setAnimationStateHandler(AnimationStateHandler handler) {
@@ -272,10 +267,9 @@ public class HeadsUpManagerPhone extends BaseHeadsUpManager implements
}
private void onShadeOrQsExpanded(Boolean isExpanded) {
- NotificationsHeadsUpRefactor.assertInLegacyMode();
if (isExpanded != mIsExpanded) {
mIsExpanded = isExpanded;
- if (isExpanded) {
+ if (!NotificationsHeadsUpRefactor.isEnabled() && isExpanded) {
mHeadsUpAnimatingAway.setValue(false);
}
}
@@ -385,8 +379,6 @@ public class HeadsUpManagerPhone extends BaseHeadsUpManager implements
private final OnReorderingAllowedListener mOnReorderingAllowedListener = () -> {
mAnimationStateHandler.setHeadsUpGoingAwayAnimationsAllowed(false);
- mAvalancheController.setEnableAtRuntime(true);
-
for (NotificationEntry entry : mEntriesToRemoveWhenReorderingAllowed) {
if (isHeadsUpEntry(entry.getKey())) {
// Maybe the heads-up was removed already
@@ -397,29 +389,6 @@ public class HeadsUpManagerPhone extends BaseHeadsUpManager implements
mAnimationStateHandler.setHeadsUpGoingAwayAnimationsAllowed(true);
};
- private final OnReorderingBannedListener mOnReorderingBannedListener = () -> {
- if (mAvalancheController != null) {
- // Waiting HUNs in AvalancheController are still promoted to the HUN section and thus
- // seen in open shade; clear them so we don't show them again when the shade closes and
- // reordering is allowed again.
- final int numDropped = mAvalancheController.getWaitingKeys().size();
- mAvalancheController.logDroppedHunsInBackground(numDropped);
- mAvalancheController.clearNext();
-
- // In open shade the first HUN is pinned, and visual stability logic prevents us from
- // unpinning this first HUN as long as the shade remains open. AvalancheController only
- // shows the next HUN when the currently showing HUN is unpinned, so we must disable
- // throttling here so that the incoming HUN stream is not forever paused. This is reset
- // when reorder becomes allowed.
- mAvalancheController.setEnableAtRuntime(false);
-
- // Note that we cannot do the above when
- // 1) the remove runnable runs because its delay means it may not run before shade close
- // 2) reordering is allowed again (when shade closes) because the HUN appear animation
- // will have started by then
- }
- };
-
///////////////////////////////////////////////////////////////////////////////////////////////
// HeadsUpManager utility (protected) methods overrides:
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index d0a62e77539f..84e601848b91 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -455,8 +455,8 @@ public class KeyguardStatusBarView extends RelativeLayout {
float luminance = Color.luminance(textColor);
@ColorInt int iconColor = Utils.getColorStateListDefaultColor(mContext,
luminance < 0.5
- ? com.android.settingslib.R.color.black
- : com.android.settingslib.R.color.white);
+ ? com.android.settingslib.R.color.dark_mode_icon_color_single_tone
+ : com.android.settingslib.R.color.light_mode_icon_color_single_tone);
@ColorInt int contrastColor = luminance < 0.5
? DarkIconDispatcherImpl.DEFAULT_ICON_TINT
: DarkIconDispatcherImpl.DEFAULT_INVERSE_ICON_TINT;
@@ -467,7 +467,7 @@ public class KeyguardStatusBarView extends RelativeLayout {
if (userSwitcherName != null) {
userSwitcherName.setTextColor(Utils.getColorStateListDefaultColor(
mContext,
- com.android.settingslib.R.color.white));
+ com.android.settingslib.R.color.light_mode_icon_color_single_tone));
}
if (iconManager != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LetterboxAppearanceCalculator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LetterboxAppearanceCalculator.kt
index 824415eaea05..231a8c65a246 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LetterboxAppearanceCalculator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LetterboxAppearanceCalculator.kt
@@ -39,7 +39,7 @@ data class LetterboxAppearance(
) {
override fun toString(): String {
val appearanceString =
- ViewDebug.flagsToString(InsetsFlags::class.java, "appearance", appearance)
+ ViewDebug.flagsToString(InsetsFlags::class.java, "appearance", appearance)
return "LetterboxAppearance{$appearanceString, $appearanceRegions}"
}
}
@@ -57,16 +57,14 @@ constructor(
private val letterboxBackgroundProvider: LetterboxBackgroundProvider,
) : Dumpable {
- private val darkAppearanceIconColor =
- context.getColor(
- // For a dark background status bar, use a *light* icon color.
- com.android.settingslib.R.color.white
- )
- private val lightAppearanceIconColor =
- context.getColor(
- // For a light background status bar, use a *dark* icon color.
- com.android.settingslib.R.color.black
- )
+ private val darkAppearanceIconColor = context.getColor(
+ // For a dark background status bar, use a *light* icon color.
+ com.android.settingslib.R.color.light_mode_icon_color_single_tone
+ )
+ private val lightAppearanceIconColor = context.getColor(
+ // For a light background status bar, use a *dark* icon color.
+ com.android.settingslib.R.color.dark_mode_icon_color_single_tone
+ )
init {
dumpManager.registerCriticalDumpable(this)
@@ -87,11 +85,7 @@ constructor(
lastAppearanceRegions = originalAppearanceRegions
lastLetterboxes = letterboxes
return getLetterboxAppearanceInternal(
- letterboxes,
- originalAppearance,
- originalAppearanceRegions,
- statusBarBounds
- )
+ letterboxes, originalAppearance, originalAppearanceRegions, statusBarBounds)
.also { lastLetterboxAppearance = it }
}
@@ -144,9 +138,7 @@ constructor(
// full bounds of its window.
// Here we want the bounds to be only for the inner bounds of the letterboxed app.
AppearanceRegion(
- appearanceRegion.appearance,
- matchingLetterbox.letterboxInnerBounds
- )
+ appearanceRegion.appearance, matchingLetterbox.letterboxInnerBounds)
}
}
@@ -156,8 +148,7 @@ constructor(
): LetterboxAppearance {
return LetterboxAppearance(
originalAppearance or APPEARANCE_SEMI_TRANSPARENT_STATUS_BARS,
- originalAppearanceRegions
- )
+ originalAppearanceRegions)
}
@Appearance
@@ -224,9 +215,7 @@ constructor(
lastAppearanceRegion: $lastAppearanceRegions,
lastLetterboxes: $lastLetterboxes,
lastLetterboxAppearance: $lastLetterboxAppearance
- """
- .trimIndent()
- )
+ """.trimIndent())
}
}
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 e4edfa4a2bfe..069c6241491c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -474,6 +474,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
// PRIMARY_BOUNCER->GONE
collectFlow(behindScrim, mKeyguardTransitionInteractor.transition(
+ Edge.Companion.getINVALID(),
Edge.Companion.create(PRIMARY_BOUNCER, GONE)),
mBouncerToGoneTransition, mMainDispatcher);
collectFlow(behindScrim, mPrimaryBouncerToGoneTransitionViewModel.getScrimAlpha(),
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt
index 507759c037ba..68163b28dd09 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt
@@ -325,7 +325,7 @@ class MobileIconInteractorImpl(
}
.stateIn(scope, SharingStarted.WhileSubscribed(), true)
- private val shownLevel: StateFlow<Int> =
+ private val cellularShownLevel: StateFlow<Int> =
combine(
level,
isInService,
@@ -337,15 +337,19 @@ class MobileIconInteractorImpl(
}
.stateIn(scope, SharingStarted.WhileSubscribed(), 0)
+ // Satellite level is unaffected by the isInService or inflateSignalStrength properties
+ // See b/346904529 for details
+ private val satelliteShownLevel: StateFlow<Int> = level
+
private val cellularIcon: Flow<SignalIconModel.Cellular> =
combine(
- shownLevel,
+ cellularShownLevel,
numberOfLevels,
showExclamationMark,
carrierNetworkChangeActive,
- ) { shownLevel, numberOfLevels, showExclamationMark, carrierNetworkChange ->
+ ) { cellularShownLevel, numberOfLevels, showExclamationMark, carrierNetworkChange ->
SignalIconModel.Cellular(
- shownLevel,
+ cellularShownLevel,
numberOfLevels,
showExclamationMark,
carrierNetworkChange,
@@ -353,7 +357,7 @@ class MobileIconInteractorImpl(
}
private val satelliteIcon: Flow<SignalIconModel.Satellite> =
- shownLevel.map {
+ satelliteShownLevel.map {
SignalIconModel.Satellite(
level = it,
icon =
@@ -365,7 +369,7 @@ class MobileIconInteractorImpl(
override val signalLevelIcon: StateFlow<SignalIconModel> = run {
val initial =
SignalIconModel.Cellular(
- shownLevel.value,
+ cellularShownLevel.value,
numberOfLevels.value,
showExclamationMark.value,
carrierNetworkChangeActive.value,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AvalancheController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AvalancheController.kt
index 8aabdf2a40f2..43ab3376e485 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AvalancheController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AvalancheController.kt
@@ -44,7 +44,6 @@ constructor(dumpManager: DumpManager,
private val tag = "AvalancheController"
private val debug = Compile.IS_DEBUG && Log.isLoggable(tag, Log.DEBUG)
- var enableAtRuntime = true
// HUN showing right now, in the floating state where full shade is hidden, on launcher or AOD
@VisibleForTesting var headsUpEntryShowing: HeadsUpEntry? = null
@@ -87,17 +86,13 @@ constructor(dumpManager: DumpManager,
dumpManager.registerNormalDumpable(tag, /* module */ this)
}
- fun isEnabled() : Boolean {
- return NotificationThrottleHun.isEnabled && enableAtRuntime
- }
-
fun getShowingHunKey(): String {
return getKey(headsUpEntryShowing)
}
/** Run or delay Runnable for given HeadsUpEntry */
fun update(entry: HeadsUpEntry?, runnable: Runnable, label: String) {
- if (!isEnabled()) {
+ if (!NotificationThrottleHun.isEnabled) {
runnable.run()
return
}
@@ -153,7 +148,7 @@ constructor(dumpManager: DumpManager,
* all Runnables associated with that entry.
*/
fun delete(entry: HeadsUpEntry?, runnable: Runnable, label: String) {
- if (!isEnabled()) {
+ if (!NotificationThrottleHun.isEnabled) {
runnable.run()
return
}
@@ -194,7 +189,7 @@ constructor(dumpManager: DumpManager,
* BaseHeadsUpManager.HeadsUpEntry.calculateFinishTime to shorten display duration.
*/
fun getDurationMs(entry: HeadsUpEntry, autoDismissMs: Int): Int {
- if (!isEnabled()) {
+ if (!NotificationThrottleHun.isEnabled) {
// Use default duration, like we did before AvalancheController existed
return autoDismissMs
}
@@ -243,7 +238,7 @@ constructor(dumpManager: DumpManager,
/** Return true if entry is waiting to show. */
fun isWaiting(key: String): Boolean {
- if (!isEnabled()) {
+ if (!NotificationThrottleHun.isEnabled) {
return false
}
for (entry in nextMap.keys) {
@@ -256,7 +251,7 @@ constructor(dumpManager: DumpManager,
/** Return list of keys for huns waiting */
fun getWaitingKeys(): MutableList<String> {
- if (!isEnabled()) {
+ if (!NotificationThrottleHun.isEnabled) {
return mutableListOf()
}
val keyList = mutableListOf<String>()
@@ -267,7 +262,7 @@ constructor(dumpManager: DumpManager,
}
fun getWaitingEntry(key: String): HeadsUpEntry? {
- if (!isEnabled()) {
+ if (!NotificationThrottleHun.isEnabled) {
return null
}
for (headsUpEntry in nextMap.keys) {
@@ -279,7 +274,7 @@ constructor(dumpManager: DumpManager,
}
fun getWaitingEntryList(): List<HeadsUpEntry> {
- if (!isEnabled()) {
+ if (!NotificationThrottleHun.isEnabled) {
return mutableListOf()
}
return nextMap.keys.toList()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/PolicyModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/PolicyModule.kt
index 2ce2bc83aa25..81e41d677be9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/PolicyModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/PolicyModule.kt
@@ -45,6 +45,10 @@ import com.android.systemui.qs.tiles.impl.location.domain.LocationTileMapper
import com.android.systemui.qs.tiles.impl.location.domain.interactor.LocationTileDataInteractor
import com.android.systemui.qs.tiles.impl.location.domain.interactor.LocationTileUserActionInteractor
import com.android.systemui.qs.tiles.impl.location.domain.model.LocationTileModel
+import com.android.systemui.qs.tiles.impl.modes.domain.interactor.ModesTileDataInteractor
+import com.android.systemui.qs.tiles.impl.modes.domain.interactor.ModesTileUserActionInteractor
+import com.android.systemui.qs.tiles.impl.modes.domain.model.ModesTileModel
+import com.android.systemui.qs.tiles.impl.modes.ui.ModesTileMapper
import com.android.systemui.qs.tiles.impl.sensorprivacy.SensorPrivacyToggleTileDataInteractor
import com.android.systemui.qs.tiles.impl.sensorprivacy.domain.SensorPrivacyToggleTileUserActionInteractor
import com.android.systemui.qs.tiles.impl.sensorprivacy.domain.model.SensorPrivacyToggleTileModel
@@ -85,35 +89,35 @@ interface PolicyModule {
@IntoMap
@StringKey(FLASHLIGHT_TILE_SPEC)
fun provideAirplaneModeAvailabilityInteractor(
- impl: FlashlightTileDataInteractor
+ impl: FlashlightTileDataInteractor
): QSTileAvailabilityInteractor
@Binds
@IntoMap
@StringKey(LOCATION_TILE_SPEC)
fun provideLocationAvailabilityInteractor(
- impl: LocationTileDataInteractor
+ impl: LocationTileDataInteractor
): QSTileAvailabilityInteractor
@Binds
@IntoMap
@StringKey(ALARM_TILE_SPEC)
fun provideAlarmAvailabilityInteractor(
- impl: AlarmTileDataInteractor
+ impl: AlarmTileDataInteractor
): QSTileAvailabilityInteractor
@Binds
@IntoMap
@StringKey(UIMODENIGHT_TILE_SPEC)
fun provideUiModeNightAvailabilityInteractor(
- impl: UiModeNightTileDataInteractor
+ impl: UiModeNightTileDataInteractor
): QSTileAvailabilityInteractor
@Binds
@IntoMap
@StringKey(WORK_MODE_TILE_SPEC)
fun provideWorkModeAvailabilityInteractor(
- impl: WorkModeTileDataInteractor
+ impl: WorkModeTileDataInteractor
): QSTileAvailabilityInteractor
companion object {
@@ -125,6 +129,7 @@ interface PolicyModule {
const val CAMERA_TOGGLE_TILE_SPEC = "cameratoggle"
const val MIC_TOGGLE_TILE_SPEC = "mictoggle"
const val DND_TILE_SPEC = "dnd"
+ const val MODES_TILE_SPEC = "modes"
/** Inject flashlight config */
@Provides
@@ -327,7 +332,7 @@ interface PolicyModule {
@IntoMap
@StringKey(CAMERA_TOGGLE_TILE_SPEC)
fun provideCameraToggleAvailabilityInteractor(
- factory: SensorPrivacyToggleTileDataInteractor.Factory
+ factory: SensorPrivacyToggleTileDataInteractor.Factory
): QSTileAvailabilityInteractor {
return factory.create(CAMERA)
}
@@ -369,12 +374,11 @@ interface PolicyModule {
@IntoMap
@StringKey(MIC_TOGGLE_TILE_SPEC)
fun provideMicToggleModeAvailabilityInteractor(
- factory: SensorPrivacyToggleTileDataInteractor.Factory
+ factory: SensorPrivacyToggleTileDataInteractor.Factory
): QSTileAvailabilityInteractor {
return factory.create(MICROPHONE)
}
-
/** Inject microphone toggle config */
@Provides
@IntoMap
@@ -389,6 +393,37 @@ interface PolicyModule {
),
instanceId = uiEventLogger.getNewInstanceId(),
)
+
+ @Provides
+ @IntoMap
+ @StringKey(MODES_TILE_SPEC)
+ fun provideModesTileConfig(uiEventLogger: QsEventLogger): QSTileConfig =
+ QSTileConfig(
+ tileSpec = TileSpec.create(MODES_TILE_SPEC),
+ uiConfig =
+ QSTileUIConfig.Resource(
+ iconRes = R.drawable.qs_dnd_icon_off,
+ labelRes = R.string.quick_settings_modes_label,
+ ),
+ instanceId = uiEventLogger.getNewInstanceId(),
+ )
+
+ /** Inject ModesTile into tileViewModelMap in QSModule */
+ @Provides
+ @IntoMap
+ @StringKey(MODES_TILE_SPEC)
+ fun provideModesTileViewModel(
+ factory: QSTileViewModelFactory.Static<ModesTileModel>,
+ mapper: ModesTileMapper,
+ stateInteractor: ModesTileDataInteractor,
+ userActionInteractor: ModesTileUserActionInteractor
+ ): QSTileViewModel =
+ factory.create(
+ TileSpec.create(MODES_TILE_SPEC),
+ userActionInteractor,
+ stateInteractor,
+ mapper,
+ )
}
/** Inject FlashlightTile into tileMap in QSModule */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SplitShadeStateController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SplitShadeStateController.kt
index d120a1bd3840..72d093c65a91 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SplitShadeStateController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SplitShadeStateController.kt
@@ -22,10 +22,10 @@ interface SplitShadeStateController {
/** Returns true if the device should use the split notification shade. */
@Deprecated(
- message = "This is deprecated, please use ShadeInteractor#isSplitShade instead",
+ message = "This is deprecated, please use ShadeInteractor#shadeMode instead",
replaceWith =
ReplaceWith(
- "shadeInteractor.isSplitShade",
+ "shadeInteractor.shadeMode",
"com.android.systemui.shade.domain.interactor.ShadeInteractor",
),
)
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunablePadding.java b/packages/SystemUI/src/com/android/systemui/tuner/TunablePadding.java
deleted file mode 100644
index d54c07c87b40..000000000000
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunablePadding.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT 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.tuner;
-
-import android.util.DisplayMetrics;
-import android.view.View;
-import android.view.WindowManager;
-
-import com.android.systemui.Dependency;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.tuner.TunerService.Tunable;
-
-import javax.inject.Inject;
-
-/**
- * Version of Space that can be resized by a tunable setting.
- */
-public class TunablePadding implements Tunable {
-
- public static final int FLAG_START = 1;
- public static final int FLAG_END = 2;
- public static final int FLAG_TOP = 4;
- public static final int FLAG_BOTTOM = 8;
-
- private final int mFlags;
- private final View mView;
- private final int mDefaultSize;
- private final float mDensity;
- private final TunerService mTunerService;
-
- private TunablePadding(String key, int def, int flags, View view, TunerService tunerService) {
- mDefaultSize = def;
- mFlags = flags;
- mView = view;
- DisplayMetrics metrics = new DisplayMetrics();
- view.getContext().getSystemService(WindowManager.class)
- .getDefaultDisplay().getMetrics(metrics);
- mDensity = metrics.density;
- mTunerService = tunerService;
- mTunerService.addTunable(this, key);
- }
-
- @Override
- public void onTuningChanged(String key, String newValue) {
- int dimen = mDefaultSize;
- if (newValue != null) {
- try {
- dimen = (int) (Integer.parseInt(newValue) * mDensity);
- } catch (NumberFormatException ex) {}
- }
- int left = mView.isLayoutRtl() ? FLAG_END : FLAG_START;
- int right = mView.isLayoutRtl() ? FLAG_START : FLAG_END;
- mView.setPadding(getPadding(dimen, left), getPadding(dimen, FLAG_TOP),
- getPadding(dimen, right), getPadding(dimen, FLAG_BOTTOM));
- }
-
- private int getPadding(int dimen, int flag) {
- return ((mFlags & flag) != 0) ? dimen : 0;
- }
-
- public void destroy() {
- mTunerService.removeTunable(this);
- }
-
- /**
- * Exists for easy injecting in tests.
- */
- @SysUISingleton
- public static class TunablePaddingService {
-
- private final TunerService mTunerService;
-
- /**
- */
- @Inject
- public TunablePaddingService(TunerService tunerService) {
- mTunerService = tunerService;
- }
-
- public TunablePadding add(View view, String key, int defaultSize, int flags) {
- if (view == null) {
- throw new IllegalArgumentException();
- }
- return new TunablePadding(key, defaultSize, flags, view, mTunerService);
- }
- }
-
- public static TunablePadding addTunablePadding(View view, String key, int defaultSize,
- int flags) {
- return Dependency.get(TunablePaddingService.class).add(view, key, defaultSize, flags);
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/util/ConvenienceExtensions.kt b/packages/SystemUI/src/com/android/systemui/util/ConvenienceExtensions.kt
index ec7aabb58b49..f2132248e4f7 100644
--- a/packages/SystemUI/src/com/android/systemui/util/ConvenienceExtensions.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/ConvenienceExtensions.kt
@@ -20,6 +20,7 @@ import android.graphics.Rect
import android.util.IndentingPrintWriter
import android.view.View
import android.view.ViewGroup
+import dagger.Lazy
import java.io.PrintWriter
/** [Sequence] that yields all of the direct children of this [ViewGroup] */
@@ -56,3 +57,8 @@ val View.boundsOnScreen: Rect
getBoundsOnScreen(bounds)
return bounds
}
+
+/** Extension method to convert [dagger.Lazy] to [kotlin.Lazy] for object of any class [T]. */
+fun <T> Lazy<T>.toKotlinLazy(): kotlin.Lazy<T> {
+ return lazy { this.get() }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/ReduceBrightColorsControllerExt.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/ReduceBrightColorsControllerExt.kt
index ee00e8b04ef1..e6e2a0767012 100644
--- a/packages/SystemUI/src/com/android/systemui/util/kotlin/ReduceBrightColorsControllerExt.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/ReduceBrightColorsControllerExt.kt
@@ -35,3 +35,17 @@ fun ReduceBrightColorsController.isEnabled(): Flow<Boolean> {
}
.onStart { emit(isReduceBrightColorsActivated) }
}
+
+fun ReduceBrightColorsController.isAvailable(): Flow<Boolean> {
+ return conflatedCallbackFlow {
+ val callback =
+ object : ReduceBrightColorsController.Listener {
+ override fun onFeatureEnabledChanged(enabled: Boolean) {
+ trySend(enabled)
+ }
+ }
+ addCallback(callback)
+ awaitClose { removeCallback(callback) }
+ }
+ .onStart { emit(isReduceBrightColorsFeatureAvailable) }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.kt b/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.kt
index fe540445793e..b5934ec680d3 100644
--- a/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.kt
@@ -19,6 +19,7 @@ import android.content.ContentResolver
import android.database.ContentObserver
import android.net.Uri
import android.provider.Settings.SettingNotFoundException
+import androidx.annotation.AnyThread
import androidx.annotation.WorkerThread
import com.android.app.tracing.TraceUtils.trace
import kotlinx.coroutines.CoroutineDispatcher
@@ -57,7 +58,7 @@ interface SettingsProxy {
* @param name to look up in the table
* @return the corresponding content URI, or null if not present
*/
- fun getUriFor(name: String): Uri
+ @AnyThread fun getUriFor(name: String): Uri
/**
* Registers listener for a given content observer <b>while blocking the current thread</b>.
@@ -89,12 +90,31 @@ interface SettingsProxy {
*
* API corresponding to [registerContentObserver] for Java usage.
*/
+ @AnyThread
fun registerContentObserverAsync(name: String, settingsObserver: ContentObserver) =
CoroutineScope(backgroundDispatcher).launch {
registerContentObserverSync(getUriFor(name), settingsObserver)
}
/**
+ * Convenience wrapper around [ContentResolver.registerContentObserver].'
+ *
+ * API corresponding to [registerContentObserver] for Java usage. After registration is
+ * complete, the callback block is called on the <b>background thread</b> to allow for update of
+ * value.
+ */
+ @AnyThread
+ fun registerContentObserverAsync(
+ name: String,
+ settingsObserver: ContentObserver,
+ @WorkerThread registered: Runnable
+ ) =
+ CoroutineScope(backgroundDispatcher).launch {
+ registerContentObserverSync(getUriFor(name), settingsObserver)
+ registered.run()
+ }
+
+ /**
* Registers listener for a given content observer <b>while blocking the current thread</b>.
*
* This should not be called from the main thread, use [registerContentObserver] or
@@ -120,6 +140,7 @@ interface SettingsProxy {
*
* API corresponding to [registerContentObserver] for Java usage.
*/
+ @AnyThread
fun registerContentObserverAsync(uri: Uri, settingsObserver: ContentObserver) =
CoroutineScope(backgroundDispatcher).launch {
registerContentObserverSync(uri, settingsObserver)
@@ -128,8 +149,27 @@ interface SettingsProxy {
/**
* Convenience wrapper around [ContentResolver.registerContentObserver].'
*
+ * API corresponding to [registerContentObserver] for Java usage. After registration is
+ * complete, the callback block is called on the <b>background thread</b> to allow for update of
+ * value.
+ */
+ @AnyThread
+ fun registerContentObserverAsync(
+ uri: Uri,
+ settingsObserver: ContentObserver,
+ @WorkerThread registered: Runnable
+ ) =
+ CoroutineScope(backgroundDispatcher).launch {
+ registerContentObserverSync(uri, settingsObserver)
+ registered.run()
+ }
+
+ /**
+ * Convenience wrapper around [ContentResolver.registerContentObserver].'
+ *
* Implicitly calls [getUriFor] on the passed in name.
*/
+ @WorkerThread
fun registerContentObserverSync(
name: String,
notifyForDescendants: Boolean,
@@ -158,6 +198,7 @@ interface SettingsProxy {
*
* API corresponding to [registerContentObserver] for Java usage.
*/
+ @AnyThread
fun registerContentObserverAsync(
name: String,
notifyForDescendants: Boolean,
@@ -168,6 +209,25 @@ interface SettingsProxy {
}
/**
+ * Convenience wrapper around [ContentResolver.registerContentObserver].'
+ *
+ * API corresponding to [registerContentObserver] for Java usage. After registration is
+ * complete, the callback block is called on the <b>background thread</b> to allow for update of
+ * value.
+ */
+ @AnyThread
+ fun registerContentObserverAsync(
+ name: String,
+ notifyForDescendants: Boolean,
+ settingsObserver: ContentObserver,
+ @WorkerThread registered: Runnable
+ ) =
+ CoroutineScope(backgroundDispatcher).launch {
+ registerContentObserverSync(getUriFor(name), notifyForDescendants, settingsObserver)
+ registered.run()
+ }
+
+ /**
* Registers listener for a given content observer <b>while blocking the current thread</b>.
*
* This should not be called from the main thread, use [registerContentObserver] or
@@ -207,6 +267,7 @@ interface SettingsProxy {
*
* API corresponding to [registerContentObserver] for Java usage.
*/
+ @AnyThread
fun registerContentObserverAsync(
uri: Uri,
notifyForDescendants: Boolean,
@@ -217,6 +278,25 @@ interface SettingsProxy {
}
/**
+ * Convenience wrapper around [ContentResolver.registerContentObserver].'
+ *
+ * API corresponding to [registerContentObserver] for Java usage. After registration is
+ * complete, the callback block is called on the <b>background thread</b> to allow for update of
+ * value.
+ */
+ @AnyThread
+ fun registerContentObserverAsync(
+ uri: Uri,
+ notifyForDescendants: Boolean,
+ settingsObserver: ContentObserver,
+ @WorkerThread registered: Runnable
+ ) =
+ CoroutineScope(backgroundDispatcher).launch {
+ registerContentObserverSync(uri, notifyForDescendants, settingsObserver)
+ registered.run()
+ }
+
+ /**
* Unregisters the given content observer <b>while blocking the current thread</b>.
*
* This should not be called from the main thread, use [unregisterContentObserver] or
@@ -246,6 +326,7 @@ interface SettingsProxy {
* API corresponding to [unregisterContentObserver] for Java usage to ensure that
* [ContentObserver] registration happens on a worker thread.
*/
+ @AnyThread
fun unregisterContentObserverAsync(settingsObserver: ContentObserver) =
CoroutineScope(backgroundDispatcher).launch { unregisterContentObserver(settingsObserver) }
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/UserSettingsProxy.kt b/packages/SystemUI/src/com/android/systemui/util/settings/UserSettingsProxy.kt
index 3bf5b6511eb3..025354b51133 100644
--- a/packages/SystemUI/src/com/android/systemui/util/settings/UserSettingsProxy.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/settings/UserSettingsProxy.kt
@@ -21,6 +21,7 @@ import android.database.ContentObserver
import android.net.Uri
import android.os.UserHandle
import android.provider.Settings.SettingNotFoundException
+import androidx.annotation.WorkerThread
import com.android.app.tracing.TraceUtils.trace
import com.android.systemui.settings.UserTracker
import com.android.systemui.util.settings.SettingsProxy.Companion.parseFloat
@@ -199,6 +200,24 @@ interface UserSettingsProxy : SettingsProxy {
}
/**
+ * Convenience wrapper around [ContentResolver.registerContentObserver].'
+ *
+ * API corresponding to [registerContentObserverForUser] for Java usage. After registration is
+ * complete, the callback block is called on the <b>background thread</b> to allow for update of
+ * value.
+ */
+ fun registerContentObserverForUserAsync(
+ uri: Uri,
+ settingsObserver: ContentObserver,
+ userHandle: Int,
+ @WorkerThread registered: Runnable
+ ) =
+ CoroutineScope(backgroundDispatcher).launch {
+ registerContentObserverForUserSync(uri, settingsObserver, userHandle)
+ registered.run()
+ }
+
+ /**
* Convenience wrapper around [ContentResolver.registerContentObserver]
*
* Implicitly calls [getUriFor] on the passed in name.
diff --git a/packages/SystemUI/src/com/android/systemui/volume/CsdWarningDialog.java b/packages/SystemUI/src/com/android/systemui/volume/CsdWarningDialog.java
index bd698ab8ad5c..bb230e6b0305 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/CsdWarningDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/CsdWarningDialog.java
@@ -30,21 +30,31 @@ import android.content.IntentFilter;
import android.media.AudioManager;
import android.provider.Settings;
import android.util.Log;
+import android.util.Pair;
import android.view.KeyEvent;
import android.view.WindowManager;
+import androidx.annotation.VisibleForTesting;
+
import com.android.internal.annotations.GuardedBy;
import com.android.internal.messages.nano.SystemMessageProto;
+import com.android.systemui.Flags;
+import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.plugins.VolumeDialog;
import com.android.systemui.res.R;
import com.android.systemui.statusbar.phone.SystemUIDialog;
import com.android.systemui.util.NotificationChannels;
import com.android.systemui.util.concurrency.DelayableExecutor;
+import com.google.common.collect.ImmutableList;
+
import dagger.assisted.Assisted;
import dagger.assisted.AssistedFactory;
import dagger.assisted.AssistedInject;
+import java.util.Optional;
+
/**
* A class that implements the three Computed Sound Dose-related warnings defined in
* {@link AudioManager}:
@@ -75,6 +85,9 @@ public class CsdWarningDialog extends SystemUIDialog
private static final int KEY_CONFIRM_ALLOWED_AFTER_MS = 1000; // milliseconds
// time after which action is taken when the user hasn't ack'd or dismissed the dialog
public static final int NO_ACTION_TIMEOUT_MS = 5000;
+ // Notification dismiss intent
+ private static final String DISMISS_CSD_NOTIFICATION =
+ "com.android.systemui.volume.DISMISS_CSD_NOTIFICATION";
private final Context mContext;
private final AudioManager mAudioManager;
@@ -95,21 +108,32 @@ public class CsdWarningDialog extends SystemUIDialog
private long mShowTime;
+ @VisibleForTesting public int mCachedMediaStreamVolume;
+ private Optional<ImmutableList<Pair<String, Intent>>> mActionIntents;
+ private final BroadcastDispatcher mBroadcastDispatcher;
+
/**
* To inject dependencies and allow for easier testing
*/
@AssistedFactory
public interface Factory {
- /**
- * Create a dialog object
- */
- CsdWarningDialog create(int csdWarning, Runnable onCleanup);
+ /** Create a dialog object */
+ CsdWarningDialog create(
+ int csdWarning,
+ Runnable onCleanup,
+ Optional<ImmutableList<Pair<String, Intent>>> actionIntents);
}
@AssistedInject
- public CsdWarningDialog(@Assisted @AudioManager.CsdWarning int csdWarning, Context context,
- AudioManager audioManager, NotificationManager notificationManager,
- @Background DelayableExecutor delayableExecutor, @Assisted Runnable onCleanup) {
+ public CsdWarningDialog(
+ @Assisted @AudioManager.CsdWarning int csdWarning,
+ Context context,
+ AudioManager audioManager,
+ NotificationManager notificationManager,
+ @Background DelayableExecutor delayableExecutor,
+ @Assisted Runnable onCleanup,
+ @Assisted Optional<ImmutableList<Pair<String, Intent>>> actionIntents,
+ BroadcastDispatcher broadcastDispatcher) {
super(context);
mCsdWarning = csdWarning;
mContext = context;
@@ -118,7 +142,8 @@ public class CsdWarningDialog extends SystemUIDialog
mOnCleanup = onCleanup;
mDelayableExecutor = delayableExecutor;
-
+ mActionIntents = actionIntents;
+ mBroadcastDispatcher = broadcastDispatcher;
getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
setShowForAllUsers(true);
setMessage(mContext.getString(getStringForWarning(csdWarning)));
@@ -133,14 +158,17 @@ public class CsdWarningDialog extends SystemUIDialog
Context.RECEIVER_EXPORTED_UNAUDITED);
if (csdWarning == AudioManager.CSD_WARNING_DOSE_REACHED_1X) {
- mNoUserActionRunnable = () -> {
- if (mCsdWarning == AudioManager.CSD_WARNING_DOSE_REACHED_1X) {
- // unlike on the 5x dose repeat, level is only reduced to RS1 when the warning
- // is not acknowledged quickly enough
- mAudioManager.lowerVolumeToRs1();
- sendNotification(/*for5XCsd=*/false);
- }
- };
+ mNoUserActionRunnable =
+ () -> {
+ if (mCsdWarning == AudioManager.CSD_WARNING_DOSE_REACHED_1X) {
+ // unlike on the 5x dose repeat, level is only reduced to RS1 when the
+ // warning is not acknowledged quickly enough
+ mCachedMediaStreamVolume =
+ mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
+ mAudioManager.lowerVolumeToRs1();
+ sendNotification(/* for5XCsd= */ false);
+ }
+ };
} else {
mNoUserActionRunnable = null;
}
@@ -242,6 +270,38 @@ public class CsdWarningDialog extends SystemUIDialog
}
};
+ @VisibleForTesting
+ public final BroadcastReceiver mReceiverUndo =
+ new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (Flags.sounddoseCustomization()
+ && VolumeDialog.ACTION_VOLUME_UNDO.equals(intent.getAction())) {
+ if (D.BUG) Log.d(TAG, "Received ACTION_VOLUME_UNDO");
+ mAudioManager.setStreamVolume(
+ AudioManager.STREAM_MUSIC,
+ mCachedMediaStreamVolume,
+ AudioManager.FLAG_SHOW_UI);
+ mNotificationManager.cancel(
+ SystemMessageProto.SystemMessage.NOTE_CSD_LOWER_AUDIO);
+ destroy();
+ }
+ }
+ };
+
+ @VisibleForTesting
+ public final BroadcastReceiver mReceiverDismissNotification =
+ new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (Flags.sounddoseCustomization()
+ && DISMISS_CSD_NOTIFICATION.equals(intent.getAction())) {
+ if (D.BUG) Log.d(TAG, "Received DISMISS_CSD_NOTIFICATION");
+ destroy();
+ }
+ }
+ };
+
private @StringRes int getStringForWarning(@AudioManager.CsdWarning int csdWarning) {
switch (csdWarning) {
case AudioManager.CSD_WARNING_DOSE_REACHED_1X:
@@ -259,7 +319,7 @@ public class CsdWarningDialog extends SystemUIDialog
Log.w(TAG, "Notification dose repeat 5x is not shown for " + mCsdWarning);
return;
}
-
+ mCachedMediaStreamVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
mAudioManager.lowerVolumeToRs1();
sendNotification(/*for5XCsd=*/true);
}
@@ -288,7 +348,62 @@ public class CsdWarningDialog extends SystemUIDialog
.setAutoCancel(true)
.setCategory(Notification.CATEGORY_SYSTEM);
+ if (Flags.sounddoseCustomization()
+ && mActionIntents.isPresent()
+ && !mActionIntents.get().isEmpty()) {
+ ImmutableList<Pair<String, Intent>> actionIntentsList = mActionIntents.get();
+ for (Pair<String, Intent> intentPair : actionIntentsList) {
+ if (intentPair != null && intentPair.first != null && intentPair.second != null) {
+ PendingIntent pendingActionIntent =
+ PendingIntent.getBroadcast(mContext, 0, intentPair.second,
+ FLAG_IMMUTABLE);
+ builder.addAction(0, intentPair.first, pendingActionIntent);
+ // Register receiver to undo volume only when
+ // notification conaining the undo action would be sent.
+ if (intentPair.first == mContext.getString(R.string.volume_undo_action)) {
+ final IntentFilter filterUndo = new IntentFilter(
+ VolumeDialog.ACTION_VOLUME_UNDO);
+ mBroadcastDispatcher.registerReceiver(mReceiverUndo,
+ filterUndo,
+ /* executor = default */ null,
+ /* user = default */ null,
+ Context.RECEIVER_NOT_EXPORTED,
+ /* permission = default */ null);
+
+ // Register receiver to learn if notification has been dismissed.
+ // This is required to unregister receivers to prevent leak.
+ Intent dismissIntent = new Intent(DISMISS_CSD_NOTIFICATION)
+ .setPackage(mContext.getPackageName());
+ PendingIntent pendingDismissIntent = PendingIntent.getBroadcast(mContext,
+ 0, dismissIntent, FLAG_IMMUTABLE);
+ mBroadcastDispatcher.registerReceiver(mReceiverDismissNotification,
+ new IntentFilter(DISMISS_CSD_NOTIFICATION),
+ /* executor = default */ null,
+ /* user = default */ null,
+ Context.RECEIVER_NOT_EXPORTED,
+ /* permission = default */ null);
+ builder.setDeleteIntent(pendingDismissIntent);
+ }
+ }
+ }
+ }
+
mNotificationManager.notify(SystemMessageProto.SystemMessage.NOTE_CSD_LOWER_AUDIO,
builder.build());
}
+
+ /**
+ * Unregister the Undo action receiver when the notification is dismissed.
+ * Unregister cannot happen when CsdWarning dialog is dismissed
+ * as the notification lifecycle would be longer.
+ */
+ @VisibleForTesting
+ public void destroy() {
+ if (Flags.sounddoseCustomization()
+ && mActionIntents.isPresent()
+ && !mActionIntents.get().isEmpty()) {
+ mBroadcastDispatcher.unregisterReceiver(mReceiverUndo);
+ mBroadcastDispatcher.unregisterReceiver(mReceiverDismissNotification);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 795d427b43bf..6b02e1ada491 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -50,6 +50,7 @@ import android.app.KeyguardManager;
import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
+import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.ColorStateList;
import android.content.res.Configuration;
@@ -77,6 +78,7 @@ import android.provider.Settings;
import android.provider.Settings.Global;
import android.text.InputFilter;
import android.util.Log;
+import android.util.Pair;
import android.util.Slog;
import android.util.SparseBooleanArray;
import android.view.ContextThemeWrapper;
@@ -140,11 +142,14 @@ import com.android.systemui.volume.domain.interactor.VolumePanelNavigationIntera
import com.android.systemui.volume.panel.shared.flag.VolumePanelFlag;
import com.android.systemui.volume.ui.navigation.VolumeNavigator;
+import com.google.common.collect.ImmutableList;
+
import dagger.Lazy;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
+import java.util.Optional;
import java.util.function.Consumer;
/**
@@ -315,6 +320,9 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable,
private final com.android.systemui.util.time.SystemClock mSystemClock;
private final VolumePanelFlag mVolumePanelFlag;
private final VolumeDialogInteractor mInteractor;
+ // Optional actions for soundDose
+ private Optional<ImmutableList<Pair<String, Intent>>> mCsdWarningNotificationActions =
+ Optional.of(ImmutableList.of());
public VolumeDialogImpl(
Context context,
@@ -2198,6 +2206,11 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable,
rescheduleTimeoutH();
}
+ public void setCsdWarningNotificationActionIntents(
+ ImmutableList<Pair<String, Intent>> actionIntent) {
+ mCsdWarningNotificationActions = Optional.of(actionIntent);
+ }
+
@VisibleForTesting void showCsdWarningH(int csdWarning, int durationMs) {
synchronized (mSafetyWarningLock) {
@@ -2212,7 +2225,8 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable,
recheckH(null);
};
- mCsdDialog = mCsdWarningDialogFactory.create(csdWarning, cleanUp);
+ mCsdDialog = mCsdWarningDialogFactory.create(
+ csdWarning, cleanUp, mCsdWarningNotificationActions);
mCsdDialog.show();
}
recheckH(null);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/TestableWindowManager.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/TestableWindowManager.java
index b23dfdc68a87..859517839388 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/TestableWindowManager.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/TestableWindowManager.java
@@ -21,6 +21,7 @@ import android.graphics.Rect;
import android.graphics.Region;
import android.os.IBinder;
import android.view.Display;
+import android.view.KeyboardShortcutGroup;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowInsets;
@@ -55,6 +56,11 @@ public class TestableWindowManager implements WindowManager {
}
@Override
+ public KeyboardShortcutGroup getApplicationLaunchKeyboardShortcuts(int deviceId) {
+ return mWindowManager.getApplicationLaunchKeyboardShortcuts(deviceId);
+ }
+
+ @Override
public Region getCurrentImeTouchRegion() {
return mWindowManager.getCurrentImeTouchRegion();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java
index c30bedde557d..12140b58936b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java
@@ -288,7 +288,7 @@ public class MenuViewLayerTest extends SysuiTestCase {
mockActivityQuery(true);
mMenuViewLayer.dispatchAccessibilityAction(R.id.action_edit);
ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
- verify(mSpyContext).startActivity(intentCaptor.capture());
+ verify(mSpyContext).startActivityAsUser(intentCaptor.capture(), eq(UserHandle.CURRENT));
assertThat(intentCaptor.getValue().getAction()).isEqualTo(
mMenuViewLayer.getIntentForEditScreen().getAction());
}
@@ -299,6 +299,7 @@ public class MenuViewLayerTest extends SysuiTestCase {
mockActivityQuery(false);
mMenuViewLayer.dispatchAccessibilityAction(R.id.action_edit);
verify(mSpyContext, never()).startActivity(any());
+ verify(mSpyContext, never()).startActivityAsUser(any(), any());
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegateTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegateTest.java
index 8f7dc7cf109b..5ea5c2189560 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegateTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegateTest.java
@@ -16,8 +16,9 @@
package com.android.systemui.accessibility.hearingaid;
+import static android.bluetooth.BluetoothHapClient.PRESET_INDEX_UNAVAILABLE;
+
import static com.android.systemui.accessibility.hearingaid.HearingDevicesDialogDelegate.LIVE_CAPTION_INTENT;
-import static com.android.systemui.statusbar.phone.SystemUIDialog.DEFAULT_DISMISS_ON_DEVICE_LOCK;
import static com.google.common.truth.Truth.assertThat;
@@ -26,9 +27,13 @@ import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHapPresetInfo;
+import android.bluetooth.BluetoothProfile;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ActivityInfo;
@@ -42,6 +47,7 @@ import android.provider.Settings;
import android.testing.TestableLooper;
import android.view.View;
import android.widget.LinearLayout;
+import android.widget.Spinner;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
@@ -86,14 +92,15 @@ public class HearingDevicesDialogDelegateTest extends SysuiTestCase {
public MockitoRule mockito = MockitoJUnit.rule();
private static final String DEVICE_ADDRESS = "AA:BB:CC:DD:EE:FF";
+ private static final String DEVICE_NAME = "test_name";
private static final String TEST_PKG = "pkg";
private static final String TEST_CLS = "cls";
private static final ComponentName TEST_COMPONENT = new ComponentName(TEST_PKG, TEST_CLS);
private static final String TEST_LABEL = "label";
+ private static final int TEST_PRESET_INDEX = 1;
+ private static final String TEST_PRESET_NAME = "test_preset";
@Mock
- private SystemUIDialog.Factory mSystemUIDialogFactory;
- @Mock
private SystemUIDialogManager mSystemUIDialogManager;
@Mock
private SysUiState mSysUiState;
@@ -118,6 +125,8 @@ public class HearingDevicesDialogDelegateTest extends SysuiTestCase {
@Mock
private CachedBluetoothDevice mCachedDevice;
@Mock
+ private BluetoothDevice mDevice;
+ @Mock
private DeviceItem mHearingDeviceItem;
@Mock
private PackageManager mPackageManager;
@@ -125,7 +134,10 @@ public class HearingDevicesDialogDelegateTest extends SysuiTestCase {
private ActivityInfo mActivityInfo;
@Mock
private Drawable mDrawable;
+ @Mock
+ private HearingDevicesPresetsController mPresetsController;
private SystemUIDialog mDialog;
+ private SystemUIDialog.Factory mDialogFactory;
private HearingDevicesDialogDelegate mDialogDelegate;
private TestableLooper mTestableLooper;
private final List<CachedBluetoothDevice> mDevices = new ArrayList<>();
@@ -141,23 +153,23 @@ public class HearingDevicesDialogDelegateTest extends SysuiTestCase {
when(mCachedDeviceManager.getCachedDevicesCopy()).thenReturn(mDevices);
when(mLocalBluetoothManager.getEventManager()).thenReturn(mBluetoothEventManager);
when(mSysUiState.setFlag(anyLong(), anyBoolean())).thenReturn(mSysUiState);
+ when(mDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+ when(mDevice.isConnected()).thenReturn(true);
+ when(mCachedDevice.getDevice()).thenReturn(mDevice);
when(mCachedDevice.getAddress()).thenReturn(DEVICE_ADDRESS);
+ when(mCachedDevice.getName()).thenReturn(DEVICE_NAME);
+ when(mCachedDevice.isActiveDevice(BluetoothProfile.HEARING_AID)).thenReturn(true);
+ when(mCachedDevice.isConnectedHearingAidDevice()).thenReturn(true);
+ when(mCachedDevice.isConnectedHapClientDevice()).thenReturn(true);
when(mHearingDeviceItem.getCachedBluetoothDevice()).thenReturn(mCachedDevice);
- mContext.setMockPackageManager(mPackageManager);
-
- setUpPairNewDeviceDialog();
- when(mSystemUIDialogFactory.create(any(SystemUIDialog.Delegate.class)))
- .thenReturn(mDialog);
- }
-
- @Test
- public void createDialog_dialogShown() {
- assertThat(mDialogDelegate.createDialog()).isEqualTo(mDialog);
+ mContext.setMockPackageManager(mPackageManager);
+ mDevices.add(mCachedDevice);
}
@Test
public void clickPairNewDeviceButton_intentActionMatch() {
+ setUpPairNewDeviceDialog();
mDialog.show();
getPairNewDeviceButton(mDialog).performClick();
@@ -185,6 +197,7 @@ public class HearingDevicesDialogDelegateTest extends SysuiTestCase {
@Test
public void onDeviceItemOnClicked_connectedDevice_disconnect() {
+ setUpDeviceListDialog();
when(mHearingDeviceItem.getType()).thenReturn(DeviceItemType.CONNECTED_BLUETOOTH_DEVICE);
mDialogDelegate.onDeviceItemOnClicked(mHearingDeviceItem, new View(mContext));
@@ -231,50 +244,100 @@ public class HearingDevicesDialogDelegateTest extends SysuiTestCase {
assertThat(relatedToolsView.getChildCount()).isEqualTo(2);
}
+ @Test
+ public void showDialog_noPreset_presetGone() {
+ when(mPresetsController.getAllPresetInfo()).thenReturn(new ArrayList<>());
+ when(mPresetsController.getActivePresetIndex()).thenReturn(PRESET_INDEX_UNAVAILABLE);
+
+ setUpDeviceListDialog();
+ mDialog.show();
+
+ Spinner spinner = (Spinner) getPresetSpinner(mDialog);
+ assertThat(spinner.getVisibility()).isEqualTo(View.GONE);
+ }
+
+ @Test
+ public void showDialog_presetExist_presetSelected() {
+ BluetoothHapPresetInfo info = getTestPresetInfo();
+ when(mPresetsController.getAllPresetInfo()).thenReturn(List.of(info));
+ when(mPresetsController.getActivePresetIndex()).thenReturn(TEST_PRESET_INDEX);
+
+ setUpDeviceListDialog();
+ mDialog.show();
+
+ Spinner spinner = (Spinner) getPresetSpinner(mDialog);
+ assertThat(spinner.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(spinner.getSelectedItemPosition()).isEqualTo(0);
+ }
+
+ @Test
+ public void onActiveDeviceChanged_presetExist_presetSelected() {
+ setUpDeviceListDialog();
+ mDialog.show();
+ BluetoothHapPresetInfo info = getTestPresetInfo();
+ when(mPresetsController.getAllPresetInfo()).thenReturn(List.of(info));
+ when(mPresetsController.getActivePresetIndex()).thenReturn(TEST_PRESET_INDEX);
+
+ mDialogDelegate.onActiveDeviceChanged(mCachedDevice, BluetoothProfile.LE_AUDIO);
+ mTestableLooper.processAllMessages();
+
+ Spinner spinner = (Spinner) getPresetSpinner(mDialog);
+ assertThat(spinner.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(spinner.getSelectedItemPosition()).isEqualTo(0);
+ }
+
+
+
private void setUpPairNewDeviceDialog() {
+ mDialogFactory = new SystemUIDialog.Factory(
+ mContext,
+ mSystemUIDialogManager,
+ mSysUiState,
+ getFakeBroadcastDispatcher(),
+ mDialogTransitionAnimator
+ );
mDialogDelegate = new HearingDevicesDialogDelegate(
mContext,
true,
- mSystemUIDialogFactory,
+ mDialogFactory,
mActivityStarter,
mDialogTransitionAnimator,
mLocalBluetoothManager,
new Handler(mTestableLooper.getLooper()),
mAudioManager
);
- mDialog = new SystemUIDialog(
+
+ mDialog = mDialogDelegate.createDialog();
+ }
+
+ private void setUpDeviceListDialog() {
+ mDialogFactory = new SystemUIDialog.Factory(
mContext,
- 0,
- DEFAULT_DISMISS_ON_DEVICE_LOCK,
mSystemUIDialogManager,
mSysUiState,
getFakeBroadcastDispatcher(),
- mDialogTransitionAnimator,
- mDialogDelegate
+ mDialogTransitionAnimator
);
- }
-
- private void setUpDeviceListDialog() {
mDialogDelegate = new HearingDevicesDialogDelegate(
mContext,
false,
- mSystemUIDialogFactory,
+ mDialogFactory,
mActivityStarter,
mDialogTransitionAnimator,
mLocalBluetoothManager,
new Handler(mTestableLooper.getLooper()),
mAudioManager
);
- mDialog = new SystemUIDialog(
- mContext,
- 0,
- DEFAULT_DISMISS_ON_DEVICE_LOCK,
- mSystemUIDialogManager,
- mSysUiState,
- getFakeBroadcastDispatcher(),
- mDialogTransitionAnimator,
- mDialogDelegate
- );
+
+ mDialog = mDialogDelegate.createDialog();
+ mDialogDelegate.setHearingDevicesPresetsController(mPresetsController);
+ }
+
+ private BluetoothHapPresetInfo getTestPresetInfo() {
+ BluetoothHapPresetInfo info = mock(BluetoothHapPresetInfo.class);
+ when(info.getName()).thenReturn(TEST_PRESET_NAME);
+ when(info.getIndex()).thenReturn(TEST_PRESET_INDEX);
+ return info;
}
private View getPairNewDeviceButton(SystemUIDialog dialog) {
@@ -285,6 +348,10 @@ public class HearingDevicesDialogDelegateTest extends SysuiTestCase {
return dialog.requireViewById(R.id.related_tools_container);
}
+ private View getPresetSpinner(SystemUIDialog dialog) {
+ return dialog.requireViewById(R.id.preset_spinner);
+ }
+
@After
public void reset() {
if (mDialogDelegate != null) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/communal/data/backup/CommunalBackupHelperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/communal/data/backup/CommunalBackupHelperTest.kt
index 7094848e3127..e60848bb6bc3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/communal/data/backup/CommunalBackupHelperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/communal/data/backup/CommunalBackupHelperTest.kt
@@ -120,11 +120,26 @@ class CommunalBackupHelperTest : SysuiTestCase() {
private fun setUpDatabase(): List<FakeWidgetMetadata> {
return listOf(
- FakeWidgetMetadata(11, "com.android.fakePackage1/fakeWidget1", 3),
- FakeWidgetMetadata(12, "com.android.fakePackage2/fakeWidget2", 2),
- FakeWidgetMetadata(13, "com.android.fakePackage3/fakeWidget3", 1),
+ FakeWidgetMetadata(
+ widgetId = 11,
+ componentName = "com.android.fakePackage1/fakeWidget1",
+ rank = 3,
+ userSerialNumber = 0,
+ ),
+ FakeWidgetMetadata(
+ widgetId = 12,
+ componentName = "com.android.fakePackage2/fakeWidget2",
+ rank = 2,
+ userSerialNumber = 0,
+ ),
+ FakeWidgetMetadata(
+ widgetId = 13,
+ componentName = "com.android.fakePackage3/fakeWidget3",
+ rank = 1,
+ userSerialNumber = 10,
+ ),
)
- .onEach { dao.addWidget(it.widgetId, it.componentName, it.rank) }
+ .onEach { dao.addWidget(it.widgetId, it.componentName, it.rank, it.userSerialNumber) }
}
private fun getBackupDataInputStream(): BackupDataInputStream {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/communal/data/backup/CommunalBackupUtilsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/communal/data/backup/CommunalBackupUtilsTest.kt
index cde7a0ed1bd4..983a43561590 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/communal/data/backup/CommunalBackupUtilsTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/communal/data/backup/CommunalBackupUtilsTest.kt
@@ -66,11 +66,28 @@ class CommunalBackupUtilsTest : SysuiTestCase() {
// Set up database
val expectedWidgets =
listOf(
- FakeWidgetMetadata(11, "com.android.fakePackage1/fakeWidget1", 3),
- FakeWidgetMetadata(12, "com.android.fakePackage2/fakeWidget2", 2),
- FakeWidgetMetadata(13, "com.android.fakePackage3/fakeWidget3", 1),
+ FakeWidgetMetadata(
+ widgetId = 11,
+ componentName = "com.android.fakePackage1/fakeWidget1",
+ rank = 3,
+ userSerialNumber = 0,
+ ),
+ FakeWidgetMetadata(
+ widgetId = 12,
+ componentName = "com.android.fakePackage2/fakeWidget2",
+ rank = 2,
+ userSerialNumber = 0,
+ ),
+ FakeWidgetMetadata(
+ widgetId = 13,
+ componentName = "com.android.fakePackage3/fakeWidget3",
+ rank = 1,
+ userSerialNumber = 10,
+ ),
)
- expectedWidgets.forEach { dao.addWidget(it.widgetId, it.componentName, it.rank) }
+ expectedWidgets.forEach {
+ dao.addWidget(it.widgetId, it.componentName, it.rank, it.userSerialNumber)
+ }
// Get communal hub state
val state = underTest.getCommunalHubState()
@@ -128,7 +145,12 @@ class CommunalBackupUtilsTest : SysuiTestCase() {
assertThat(underTest.fileExists()).isFalse()
}
- data class FakeWidgetMetadata(val widgetId: Int, val componentName: String, val rank: Int)
+ data class FakeWidgetMetadata(
+ val widgetId: Int,
+ val componentName: String,
+ val rank: Int,
+ val userSerialNumber: Int,
+ )
companion object {
/**
@@ -140,7 +162,8 @@ class CommunalBackupUtilsTest : SysuiTestCase() {
{ actual, expected ->
actual?.widgetId == expected?.widgetId &&
actual?.componentName == expected?.componentName &&
- actual?.rank == expected?.rank
+ actual?.rank == expected?.rank &&
+ actual?.userSerialNumber == expected?.userSerialNumber
},
"represents",
)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/communal/data/db/CommunalDatabaseMigrationsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/communal/data/db/CommunalDatabaseMigrationsTest.kt
new file mode 100644
index 000000000000..eb0ab782ae3f
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/communal/data/db/CommunalDatabaseMigrationsTest.kt
@@ -0,0 +1,149 @@
+/*
+ * 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.communal.data.db
+
+import androidx.room.testing.MigrationTestHelper
+import androidx.sqlite.db.SupportSQLiteDatabase
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.lifecycle.InstantTaskExecutorRule
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class CommunalDatabaseMigrationsTest : SysuiTestCase() {
+
+ @JvmField @Rule val instantTaskExecutor = InstantTaskExecutorRule()
+
+ @get:Rule
+ val migrationTestHelper =
+ MigrationTestHelper(
+ InstrumentationRegistry.getInstrumentation(),
+ CommunalDatabase::class.java.canonicalName,
+ )
+
+ @Test
+ fun migrate1To2() {
+ // Create a communal database in version 1
+ val databaseV1 = migrationTestHelper.createDatabase(DATABASE_NAME, version = 1)
+
+ // Populate some fake data
+ val fakeWidgetsV1 =
+ listOf(
+ FakeCommunalWidgetItemV1(1, "test_widget_1", 11),
+ FakeCommunalWidgetItemV1(2, "test_widget_2", 12),
+ FakeCommunalWidgetItemV1(3, "test_widget_3", 13),
+ )
+ databaseV1.insertWidgetsV1(fakeWidgetsV1)
+
+ // Verify fake widgets populated
+ databaseV1.verifyWidgetsV1(fakeWidgetsV1)
+
+ // Run migration and get database V2, the migration test helper verifies that the schema is
+ // updated correctly
+ val databaseV2 =
+ migrationTestHelper.runMigrationsAndValidate(
+ name = DATABASE_NAME,
+ version = 2,
+ validateDroppedTables = false,
+ CommunalDatabase.MIGRATION_1_2,
+ )
+
+ // Verify data is migrated correctly
+ databaseV2.verifyWidgetsV2(fakeWidgetsV1.map { it.getV2() })
+ }
+
+ private fun SupportSQLiteDatabase.insertWidgetsV1(widgets: List<FakeCommunalWidgetItemV1>) {
+ widgets.forEach { widget ->
+ execSQL(
+ "INSERT INTO communal_widget_table(widget_id, component_name, item_id) " +
+ "VALUES(${widget.widgetId}, '${widget.componentName}', ${widget.itemId})"
+ )
+ }
+ }
+
+ private fun SupportSQLiteDatabase.verifyWidgetsV1(widgets: List<FakeCommunalWidgetItemV1>) {
+ val cursor = query("SELECT * FROM communal_widget_table")
+ assertThat(cursor.moveToFirst()).isTrue()
+
+ widgets.forEach { widget ->
+ assertThat(cursor.getInt(cursor.getColumnIndex("widget_id"))).isEqualTo(widget.widgetId)
+ assertThat(cursor.getString(cursor.getColumnIndex("component_name")))
+ .isEqualTo(widget.componentName)
+ assertThat(cursor.getInt(cursor.getColumnIndex("item_id"))).isEqualTo(widget.itemId)
+
+ cursor.moveToNext()
+ }
+
+ // Verify there is no more columns
+ assertThat(cursor.isAfterLast).isTrue()
+ }
+
+ private fun SupportSQLiteDatabase.verifyWidgetsV2(widgets: List<FakeCommunalWidgetItemV2>) {
+ val cursor = query("SELECT * FROM communal_widget_table")
+ assertThat(cursor.moveToFirst()).isTrue()
+
+ widgets.forEach { widget ->
+ assertThat(cursor.getInt(cursor.getColumnIndex("widget_id"))).isEqualTo(widget.widgetId)
+ assertThat(cursor.getString(cursor.getColumnIndex("component_name")))
+ .isEqualTo(widget.componentName)
+ assertThat(cursor.getInt(cursor.getColumnIndex("item_id"))).isEqualTo(widget.itemId)
+ assertThat(cursor.getInt(cursor.getColumnIndex("user_serial_number")))
+ .isEqualTo(widget.userSerialNumber)
+
+ cursor.moveToNext()
+ }
+
+ // Verify there is no more columns
+ assertThat(cursor.isAfterLast).isTrue()
+ }
+
+ /**
+ * Returns the expected data after migration from V1 to V2, which is simply that the new user
+ * serial number field is now set to [CommunalWidgetItem.USER_SERIAL_NUMBER_UNDEFINED].
+ */
+ private fun FakeCommunalWidgetItemV1.getV2(): FakeCommunalWidgetItemV2 {
+ return FakeCommunalWidgetItemV2(
+ widgetId,
+ componentName,
+ itemId,
+ CommunalWidgetItem.USER_SERIAL_NUMBER_UNDEFINED,
+ )
+ }
+
+ private data class FakeCommunalWidgetItemV1(
+ val widgetId: Int,
+ val componentName: String,
+ val itemId: Int,
+ )
+
+ private data class FakeCommunalWidgetItemV2(
+ val widgetId: Int,
+ val componentName: String,
+ val itemId: Int,
+ val userSerialNumber: Int,
+ )
+
+ companion object {
+ private const val DATABASE_NAME = "communal_db"
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/communal/data/db/CommunalWidgetDaoTest.kt b/packages/SystemUI/tests/src/com/android/systemui/communal/data/db/CommunalWidgetDaoTest.kt
index f77c7a672ae3..d6705085eafd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/communal/data/db/CommunalWidgetDaoTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/communal/data/db/CommunalWidgetDaoTest.kt
@@ -67,11 +67,12 @@ class CommunalWidgetDaoTest : SysuiTestCase() {
@Test
fun addWidget_readValueInDb() =
testScope.runTest {
- val (widgetId, provider, priority) = widgetInfo1
+ val (widgetId, provider, priority, userSerialNumber) = widgetInfo1
communalWidgetDao.addWidget(
widgetId = widgetId,
provider = provider,
priority = priority,
+ userSerialNumber = userSerialNumber,
)
val entry = communalWidgetDao.getWidgetByIdNow(id = 1)
assertThat(entry).isEqualTo(communalWidgetItemEntry1)
@@ -80,11 +81,12 @@ class CommunalWidgetDaoTest : SysuiTestCase() {
@Test
fun deleteWidget_notInDb_returnsFalse() =
testScope.runTest {
- val (widgetId, provider, priority) = widgetInfo1
+ val (widgetId, provider, priority, userSerialNumber) = widgetInfo1
communalWidgetDao.addWidget(
widgetId = widgetId,
provider = provider,
priority = priority,
+ userSerialNumber = userSerialNumber,
)
assertThat(communalWidgetDao.deleteWidgetById(widgetId = 123)).isFalse()
}
@@ -95,11 +97,12 @@ class CommunalWidgetDaoTest : SysuiTestCase() {
val widgetsToAdd = listOf(widgetInfo1, widgetInfo2)
val widgets = collectLastValue(communalWidgetDao.getWidgets())
widgetsToAdd.forEach {
- val (widgetId, provider, priority) = it
+ val (widgetId, provider, priority, userSerialNumber) = it
communalWidgetDao.addWidget(
widgetId = widgetId,
provider = provider,
priority = priority,
+ userSerialNumber = userSerialNumber
)
}
assertThat(widgets())
@@ -118,11 +121,12 @@ class CommunalWidgetDaoTest : SysuiTestCase() {
val widgets = collectLastValue(communalWidgetDao.getWidgets())
widgetsToAdd.forEach {
- val (widgetId, provider, priority) = it
+ val (widgetId, provider, priority, userSerialNumber) = it
communalWidgetDao.addWidget(
widgetId = widgetId,
provider = provider,
priority = priority,
+ userSerialNumber = userSerialNumber,
)
}
assertThat(widgets())
@@ -144,11 +148,12 @@ class CommunalWidgetDaoTest : SysuiTestCase() {
val widgets = collectLastValue(communalWidgetDao.getWidgets())
widgetsToAdd.forEach {
- val (widgetId, provider, priority) = it
+ val (widgetId, provider, priority, userSerialNumber) = it
communalWidgetDao.addWidget(
widgetId = widgetId,
provider = provider,
priority = priority,
+ userSerialNumber = userSerialNumber,
)
}
assertThat(widgets())
@@ -180,11 +185,12 @@ class CommunalWidgetDaoTest : SysuiTestCase() {
val widgets = collectLastValue(communalWidgetDao.getWidgets())
existingWidgets.forEach {
- val (widgetId, provider, priority) = it
+ val (widgetId, provider, priority, userSerialNumber) = it
communalWidgetDao.addWidget(
widgetId = widgetId,
provider = provider,
priority = priority,
+ userSerialNumber = userSerialNumber,
)
}
assertThat(widgets())
@@ -212,6 +218,7 @@ class CommunalWidgetDaoTest : SysuiTestCase() {
widgetId = widgetInfo3.widgetId,
provider = widgetInfo3.provider,
priority = 2,
+ userSerialNumber = widgetInfo3.userSerialNumber,
)
assertThat(widgets())
.containsExactly(
@@ -246,6 +253,7 @@ class CommunalWidgetDaoTest : SysuiTestCase() {
widgetId = fakeWidget.widgetId,
componentName = fakeWidget.componentName,
itemId = rank.uid,
+ userSerialNumber = fakeWidget.userSerialNumber,
)
expected[rank] = widget
}
@@ -258,13 +266,15 @@ class CommunalWidgetDaoTest : SysuiTestCase() {
widgetId = metadata.widgetId,
provider = metadata.provider,
priority = priority ?: metadata.priority,
+ userSerialNumber = metadata.userSerialNumber,
)
}
data class FakeWidgetMetadata(
val widgetId: Int,
val provider: ComponentName,
- val priority: Int
+ val priority: Int,
+ val userSerialNumber: Int,
)
companion object {
@@ -272,19 +282,22 @@ class CommunalWidgetDaoTest : SysuiTestCase() {
FakeWidgetMetadata(
widgetId = 1,
provider = ComponentName("pk_name", "cls_name_1"),
- priority = 1
+ priority = 1,
+ userSerialNumber = 0,
)
val widgetInfo2 =
FakeWidgetMetadata(
widgetId = 2,
provider = ComponentName("pk_name", "cls_name_2"),
- priority = 2
+ priority = 2,
+ userSerialNumber = 0,
)
val widgetInfo3 =
FakeWidgetMetadata(
widgetId = 3,
provider = ComponentName("pk_name", "cls_name_3"),
- priority = 3
+ priority = 3,
+ userSerialNumber = 10,
)
val communalItemRankEntry1 = CommunalItemRank(uid = 1L, rank = widgetInfo1.priority)
val communalItemRankEntry2 = CommunalItemRank(uid = 2L, rank = widgetInfo2.priority)
@@ -295,6 +308,7 @@ class CommunalWidgetDaoTest : SysuiTestCase() {
widgetId = widgetInfo1.widgetId,
componentName = widgetInfo1.provider.flattenToString(),
itemId = communalItemRankEntry1.uid,
+ userSerialNumber = widgetInfo1.userSerialNumber,
)
val communalWidgetItemEntry2 =
CommunalWidgetItem(
@@ -302,6 +316,7 @@ class CommunalWidgetDaoTest : SysuiTestCase() {
widgetId = widgetInfo2.widgetId,
componentName = widgetInfo2.provider.flattenToString(),
itemId = communalItemRankEntry2.uid,
+ userSerialNumber = widgetInfo2.userSerialNumber,
)
val communalWidgetItemEntry3 =
CommunalWidgetItem(
@@ -309,6 +324,7 @@ class CommunalWidgetDaoTest : SysuiTestCase() {
widgetId = widgetInfo3.widgetId,
componentName = widgetInfo3.provider.flattenToString(),
itemId = communalItemRankEntry3.uid,
+ userSerialNumber = widgetInfo3.userSerialNumber,
)
val fakeState =
CommunalHubState().apply {
@@ -318,11 +334,13 @@ class CommunalWidgetDaoTest : SysuiTestCase() {
widgetId = 1
componentName = "pk_name/fake_widget_1"
rank = 1
+ userSerialNumber = 0
},
CommunalHubState.CommunalWidgetItem().apply {
widgetId = 2
componentName = "pk_name/fake_widget_2"
rank = 2
+ userSerialNumber = 10
},
)
.toTypedArray()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt
index f34058b2a684..20cb1e129f49 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt
@@ -59,12 +59,14 @@ class DisplayRepositoryTest : SysuiTestCase() {
private val testHandler = FakeHandler(Looper.getMainLooper())
private val testScope = TestScope(UnconfinedTestDispatcher())
+ private val defaultDisplay =
+ display(type = TYPE_INTERNAL, id = DEFAULT_DISPLAY, state = Display.STATE_ON)
private lateinit var displayRepository: DisplayRepositoryImpl
@Before
fun setup() {
- setDisplays(DEFAULT_DISPLAY)
+ setDisplays(listOf(defaultDisplay))
setAllDisplaysIncludingDisabled(DEFAULT_DISPLAY)
displayRepository =
DisplayRepositoryImpl(
@@ -434,19 +436,12 @@ class DisplayRepositoryTest : SysuiTestCase() {
fun defaultDisplayOff_changes() =
testScope.runTest {
val defaultDisplayOff by latestDefaultDisplayOffFlowValue()
- setDisplays(
- listOf(
- display(type = TYPE_INTERNAL, id = DEFAULT_DISPLAY, state = Display.STATE_OFF)
- )
- )
+
+ whenever(defaultDisplay.state).thenReturn(Display.STATE_OFF)
displayListener.value.onDisplayChanged(DEFAULT_DISPLAY)
assertThat(defaultDisplayOff).isTrue()
- setDisplays(
- listOf(
- display(type = TYPE_INTERNAL, id = DEFAULT_DISPLAY, state = Display.STATE_ON)
- )
- )
+ whenever(defaultDisplay.state).thenReturn(Display.STATE_ON)
displayListener.value.onDisplayChanged(DEFAULT_DISPLAY)
assertThat(defaultDisplayOff).isFalse()
}
@@ -545,7 +540,10 @@ class DisplayRepositoryTest : SysuiTestCase() {
}
private fun setAllDisplaysIncludingDisabled(vararg ids: Int) {
- val displays = ids.map { display(type = TYPE_EXTERNAL, id = it) }.toTypedArray()
+ val displays =
+ (ids.toSet() - DEFAULT_DISPLAY) // Default display always added.
+ .map { display(type = TYPE_EXTERNAL, id = it) }
+ .toTypedArray() + defaultDisplay
whenever(
displayManager.getDisplays(
eq(DisplayManager.DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperCategoriesRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperCategoriesRepositoryTest.kt
new file mode 100644
index 000000000000..14837f219862
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperCategoriesRepositoryTest.kt
@@ -0,0 +1,90 @@
+/*
+ * 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 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.keyboard.shortcut.data.source.FakeKeyboardShortcutGroupsSource
+import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts
+import com.android.systemui.keyboard.shortcut.shortcutHelperAppCategoriesShortcutsSource
+import com.android.systemui.keyboard.shortcut.shortcutHelperCategoriesRepository
+import com.android.systemui.keyboard.shortcut.shortcutHelperCurrentAppShortcutsSource
+import com.android.systemui.keyboard.shortcut.shortcutHelperInputShortcutsSource
+import com.android.systemui.keyboard.shortcut.shortcutHelperMultiTaskingShortcutsSource
+import com.android.systemui.keyboard.shortcut.shortcutHelperSystemShortcutsSource
+import com.android.systemui.keyboard.shortcut.shortcutHelperTestHelper
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class ShortcutHelperCategoriesRepositoryTest : SysuiTestCase() {
+
+ private val fakeSystemSource = FakeKeyboardShortcutGroupsSource()
+ private val fakeMultiTaskingSource = FakeKeyboardShortcutGroupsSource()
+
+ private val kosmos =
+ testKosmos().also {
+ it.testDispatcher = UnconfinedTestDispatcher()
+ it.shortcutHelperSystemShortcutsSource = fakeSystemSource
+ it.shortcutHelperMultiTaskingShortcutsSource = fakeMultiTaskingSource
+ it.shortcutHelperAppCategoriesShortcutsSource = FakeKeyboardShortcutGroupsSource()
+ it.shortcutHelperInputShortcutsSource = FakeKeyboardShortcutGroupsSource()
+ it.shortcutHelperCurrentAppShortcutsSource = FakeKeyboardShortcutGroupsSource()
+ }
+
+ private val repo = kosmos.shortcutHelperCategoriesRepository
+ private val helper = kosmos.shortcutHelperTestHelper
+ private val testScope = kosmos.testScope
+
+ @Before
+ fun setUp() {
+ fakeSystemSource.setGroups(TestShortcuts.systemGroups)
+ fakeMultiTaskingSource.setGroups(TestShortcuts.multitaskingGroups)
+ }
+
+ @Test
+ fun categories_multipleSubscribers_replaysExistingValueToNewSubscribers() =
+ testScope.runTest {
+ fakeSystemSource.setGroups(TestShortcuts.systemGroups)
+ fakeMultiTaskingSource.setGroups(TestShortcuts.multitaskingGroups)
+ helper.showFromActivity()
+ val firstCategories by collectLastValue(repo.categories)
+
+ // Intentionally change shortcuts now. This simulates "current app" shortcuts changing
+ // when our helper is shown.
+ // We still want to return the shortcuts that were returned before our helper was
+ // showing.
+ fakeSystemSource.setGroups(emptyList())
+
+ val secondCategories by collectLastValue(repo.categories)
+ // Make sure the second subscriber receives the same value as the first subscriber, even
+ // though fetching shortcuts again would have returned a new result.
+ assertThat(secondCategories).isEqualTo(firstCategories)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt b/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt
index 765cd014864c..4fba7e355df8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt
@@ -220,7 +220,7 @@ object TestShortcuts {
val imeGroups = listOf(standardGroup1, standardGroup2, standardGroup3)
val imeCategory =
ShortcutCategory(
- type = ShortcutCategoryType.IME,
+ type = ShortcutCategoryType.InputMethodEditor,
subCategories =
listOf(
subCategoryForInputLanguageSwitchShortcuts,
@@ -233,14 +233,14 @@ object TestShortcuts {
val systemGroups = listOf(standardGroup3, standardGroup2, standardGroup1)
val systemCategory =
ShortcutCategory(
- type = ShortcutCategoryType.SYSTEM,
+ type = ShortcutCategoryType.System,
subCategories = listOf(standardSubCategory3, standardSubCategory2, standardSubCategory1)
)
val multitaskingGroups = listOf(standardGroup2, standardGroup1)
val multitaskingCategory =
ShortcutCategory(
- type = ShortcutCategoryType.MULTI_TASKING,
+ type = ShortcutCategoryType.MultiTasking,
subCategories = listOf(standardSubCategory2, standardSubCategory1)
)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractorTest.kt
index 4c1e8696cdc1..57c8b444b922 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractorTest.kt
@@ -23,11 +23,12 @@ import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.keyboard.shortcut.data.source.FakeKeyboardShortcutGroupsSource
import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategory
-import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.IME
-import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.MULTI_TASKING
-import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.SYSTEM
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.InputMethodEditor
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.MultiTasking
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.System
import com.android.systemui.keyboard.shortcut.shortcutHelperAppCategoriesShortcutsSource
import com.android.systemui.keyboard.shortcut.shortcutHelperCategoriesInteractor
+import com.android.systemui.keyboard.shortcut.shortcutHelperCurrentAppShortcutsSource
import com.android.systemui.keyboard.shortcut.shortcutHelperMultiTaskingShortcutsSource
import com.android.systemui.keyboard.shortcut.shortcutHelperSystemShortcutsSource
import com.android.systemui.keyboard.shortcut.shortcutHelperTestHelper
@@ -48,14 +49,14 @@ class ShortcutHelperCategoriesInteractorTest : SysuiTestCase() {
private val systemShortcutsSource = FakeKeyboardShortcutGroupsSource()
private val multitaskingShortcutsSource = FakeKeyboardShortcutGroupsSource()
- private val defaultAppsShortcutsSource = FakeKeyboardShortcutGroupsSource()
@OptIn(ExperimentalCoroutinesApi::class)
private val kosmos =
testKosmos().also {
it.testDispatcher = UnconfinedTestDispatcher()
it.shortcutHelperSystemShortcutsSource = systemShortcutsSource
it.shortcutHelperMultiTaskingShortcutsSource = multitaskingShortcutsSource
- it.shortcutHelperAppCategoriesShortcutsSource = defaultAppsShortcutsSource
+ it.shortcutHelperAppCategoriesShortcutsSource = FakeKeyboardShortcutGroupsSource()
+ it.shortcutHelperCurrentAppShortcutsSource = FakeKeyboardShortcutGroupsSource()
}
private val testScope = kosmos.testScope
@@ -117,7 +118,7 @@ class ShortcutHelperCategoriesInteractorTest : SysuiTestCase() {
TestShortcuts.systemCategory,
TestShortcuts.multitaskingCategory,
ShortcutCategory(
- type = IME,
+ type = InputMethodEditor,
subCategories =
TestShortcuts.imeSubCategoriesWithGroupedDuplicatedShortcutLabels
),
@@ -137,7 +138,7 @@ class ShortcutHelperCategoriesInteractorTest : SysuiTestCase() {
assertThat(categories)
.containsExactly(
ShortcutCategory(
- type = SYSTEM,
+ type = System,
subCategories =
TestShortcuts.subCategoriesWithGroupedDuplicatedShortcutLabels
),
@@ -160,7 +161,7 @@ class ShortcutHelperCategoriesInteractorTest : SysuiTestCase() {
.containsExactly(
TestShortcuts.systemCategory,
ShortcutCategory(
- type = MULTI_TASKING,
+ type = MultiTasking,
subCategories =
TestShortcuts.subCategoriesWithGroupedDuplicatedShortcutLabels
),
@@ -182,7 +183,7 @@ class ShortcutHelperCategoriesInteractorTest : SysuiTestCase() {
TestShortcuts.systemCategory,
TestShortcuts.multitaskingCategory,
ShortcutCategory(
- type = IME,
+ type = InputMethodEditor,
subCategories =
TestShortcuts.imeSubCategoriesWithUnsupportedModifiersRemoved
),
@@ -201,7 +202,7 @@ class ShortcutHelperCategoriesInteractorTest : SysuiTestCase() {
assertThat(categories)
.containsExactly(
ShortcutCategory(
- type = SYSTEM,
+ type = System,
subCategories = TestShortcuts.subCategoriesWithUnsupportedModifiersRemoved
),
TestShortcuts.multitaskingCategory,
@@ -222,7 +223,7 @@ class ShortcutHelperCategoriesInteractorTest : SysuiTestCase() {
.containsExactly(
TestShortcuts.systemCategory,
ShortcutCategory(
- type = MULTI_TASKING,
+ type = MultiTasking,
subCategories = TestShortcuts.subCategoriesWithUnsupportedModifiersRemoved
),
TestShortcuts.imeCategory,
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
index 0757ea156bbf..f8e2f47f939a 100644
--- 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
@@ -20,8 +20,15 @@ import android.content.Intent
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.keyboard.shortcut.data.source.FakeKeyboardShortcutGroupsSource
+import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts
import com.android.systemui.keyboard.shortcut.fakeShortcutHelperStartActivity
import com.android.systemui.keyboard.shortcut.shortcutHelperActivityStarter
+import com.android.systemui.keyboard.shortcut.shortcutHelperAppCategoriesShortcutsSource
+import com.android.systemui.keyboard.shortcut.shortcutHelperCurrentAppShortcutsSource
+import com.android.systemui.keyboard.shortcut.shortcutHelperInputShortcutsSource
+import com.android.systemui.keyboard.shortcut.shortcutHelperMultiTaskingShortcutsSource
+import com.android.systemui.keyboard.shortcut.shortcutHelperSystemShortcutsSource
import com.android.systemui.keyboard.shortcut.shortcutHelperTestHelper
import com.android.systemui.keyboard.shortcut.ui.view.ShortcutHelperActivity
import com.android.systemui.kosmos.Kosmos
@@ -32,6 +39,7 @@ import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest
+import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -40,10 +48,18 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class ShortcutHelperActivityStarterTest : SysuiTestCase() {
+ private val fakeSystemSource = FakeKeyboardShortcutGroupsSource()
+ private val fakeMultiTaskingSource = FakeKeyboardShortcutGroupsSource()
+
private val kosmos =
Kosmos().also {
it.testCase = this
it.testDispatcher = UnconfinedTestDispatcher()
+ it.shortcutHelperSystemShortcutsSource = fakeSystemSource
+ it.shortcutHelperMultiTaskingShortcutsSource = fakeMultiTaskingSource
+ it.shortcutHelperAppCategoriesShortcutsSource = FakeKeyboardShortcutGroupsSource()
+ it.shortcutHelperInputShortcutsSource = FakeKeyboardShortcutGroupsSource()
+ it.shortcutHelperCurrentAppShortcutsSource = FakeKeyboardShortcutGroupsSource()
}
private val testScope = kosmos.testScope
@@ -51,6 +67,12 @@ class ShortcutHelperActivityStarterTest : SysuiTestCase() {
private val fakeStartActivity = kosmos.fakeShortcutHelperStartActivity
private val starter = kosmos.shortcutHelperActivityStarter
+ @Before
+ fun setUp() {
+ fakeSystemSource.setGroups(TestShortcuts.systemGroups)
+ fakeMultiTaskingSource.setGroups(TestShortcuts.multitaskingGroups)
+ }
+
@Test
fun start_doesNotStartByDefault() =
testScope.runTest {
@@ -70,13 +92,30 @@ class ShortcutHelperActivityStarterTest : SysuiTestCase() {
}
@Test
+ fun start_onToggle_noShortcuts_doesNotStartActivity() =
+ testScope.runTest {
+ fakeSystemSource.setGroups(emptyList())
+ fakeMultiTaskingSource.setGroups(emptyList())
+
+ starter.start()
+
+ testHelper.toggle(deviceId = 456)
+
+ assertThat(fakeStartActivity.startIntents).isEmpty()
+ }
+
+ @Test
fun start_onToggle_multipleTimesStartsActivityOnlyWhenNotStarted() =
testScope.runTest {
starter.start()
+ // Starts
testHelper.toggle(deviceId = 456)
+ // Stops
testHelper.toggle(deviceId = 456)
+ // Starts again
testHelper.toggle(deviceId = 456)
+ // Stops
testHelper.toggle(deviceId = 456)
verifyShortcutHelperActivityStarted(numTimes = 2)
@@ -93,6 +132,18 @@ class ShortcutHelperActivityStarterTest : SysuiTestCase() {
}
@Test
+ fun start_onRequestShowShortcuts_noShortcuts_doesNotStartActivity() =
+ testScope.runTest {
+ fakeSystemSource.setGroups(emptyList())
+ fakeMultiTaskingSource.setGroups(emptyList())
+ starter.start()
+
+ testHelper.showFromActivity()
+
+ assertThat(fakeStartActivity.startIntents).isEmpty()
+ }
+
+ @Test
fun start_onRequestShowShortcuts_multipleTimes_startsActivityOnlyOnce() =
testScope.runTest {
starter.start()
@@ -109,13 +160,21 @@ class ShortcutHelperActivityStarterTest : SysuiTestCase() {
testScope.runTest {
starter.start()
+ // No-op. Already hidden.
testHelper.hideFromActivity()
+ // No-op. Already hidden.
testHelper.hideForSystem()
+ // Show 1st time.
testHelper.toggle(deviceId = 987)
+ // No-op. Already shown.
testHelper.showFromActivity()
+ // Hidden.
testHelper.hideFromActivity()
+ // No-op. Already hidden.
testHelper.hideForSystem()
+ // Show 2nd time.
testHelper.toggle(deviceId = 456)
+ // No-op. Already shown.
testHelper.showFromActivity()
verifyShortcutHelperActivityStarted(numTimes = 2)
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
index 80d487cab50d..07feaa1a5047 100644
--- 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
@@ -21,6 +21,13 @@ 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.data.source.FakeKeyboardShortcutGroupsSource
+import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts
+import com.android.systemui.keyboard.shortcut.shortcutHelperAppCategoriesShortcutsSource
+import com.android.systemui.keyboard.shortcut.shortcutHelperCurrentAppShortcutsSource
+import com.android.systemui.keyboard.shortcut.shortcutHelperInputShortcutsSource
+import com.android.systemui.keyboard.shortcut.shortcutHelperMultiTaskingShortcutsSource
+import com.android.systemui.keyboard.shortcut.shortcutHelperSystemShortcutsSource
import com.android.systemui.keyboard.shortcut.shortcutHelperTestHelper
import com.android.systemui.keyboard.shortcut.shortcutHelperViewModel
import com.android.systemui.keyboard.shortcut.ui.model.ShortcutsUiState
@@ -34,6 +41,7 @@ import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest
+import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -42,10 +50,18 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class ShortcutHelperViewModelTest : SysuiTestCase() {
+ private val fakeSystemSource = FakeKeyboardShortcutGroupsSource()
+ private val fakeMultiTaskingSource = FakeKeyboardShortcutGroupsSource()
+
private val kosmos =
Kosmos().also {
it.testCase = this
it.testDispatcher = UnconfinedTestDispatcher()
+ it.shortcutHelperSystemShortcutsSource = fakeSystemSource
+ it.shortcutHelperMultiTaskingShortcutsSource = fakeMultiTaskingSource
+ it.shortcutHelperAppCategoriesShortcutsSource = FakeKeyboardShortcutGroupsSource()
+ it.shortcutHelperInputShortcutsSource = FakeKeyboardShortcutGroupsSource()
+ it.shortcutHelperCurrentAppShortcutsSource = FakeKeyboardShortcutGroupsSource()
}
private val testScope = kosmos.testScope
@@ -53,6 +69,12 @@ class ShortcutHelperViewModelTest : SysuiTestCase() {
private val sysUiState = kosmos.sysUiState
private val viewModel = kosmos.shortcutHelperViewModel
+ @Before
+ fun setUp() {
+ fakeSystemSource.setGroups(TestShortcuts.systemGroups)
+ fakeMultiTaskingSource.setGroups(TestShortcuts.multitaskingGroups)
+ }
+
@Test
fun shouldShow_falseByDefault() =
testScope.runTest {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ResourceTrimmerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ResourceTrimmerTest.kt
index 144e634ae519..23fd997c02e1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ResourceTrimmerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ResourceTrimmerTest.kt
@@ -18,7 +18,6 @@ import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.se
import com.android.systemui.power.domain.interactor.powerInteractor
import com.android.systemui.scene.data.repository.Idle
import com.android.systemui.scene.data.repository.setSceneTransition
-import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.testKosmos
import com.android.systemui.utils.GlobalWindowManager
@@ -64,7 +63,6 @@ class ResourceTrimmerTest : SysuiTestCase() {
globalWindowManager = globalWindowManager,
applicationScope = testScope.backgroundScope,
bgDispatcher = kosmos.testDispatcher,
- sceneInteractor = kosmos.sceneInteractor,
)
resourceTrimmer.start()
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorTest.kt
index f0ad5103e9a6..59f16d70fab5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorTest.kt
@@ -36,7 +36,6 @@ import com.android.systemui.kosmos.testScope
import com.android.systemui.plugins.clocks.ClockConfig
import com.android.systemui.plugins.clocks.ClockController
import com.android.systemui.shade.data.repository.shadeRepository
-import com.android.systemui.shade.shared.model.ShadeMode
import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.whenever
@@ -84,7 +83,7 @@ class KeyguardBlueprintInteractorTest : SysuiTestCase() {
fun testAppliesDefaultBlueprint() {
testScope.runTest {
val blueprintId by collectLastValue(underTest.blueprintId)
- kosmos.shadeRepository.setShadeMode(ShadeMode.Single)
+ kosmos.shadeRepository.setShadeLayoutWide(false)
configurationRepository.onConfigurationChange()
runCurrent()
@@ -98,7 +97,7 @@ class KeyguardBlueprintInteractorTest : SysuiTestCase() {
fun testAppliesSplitShadeBlueprint() {
testScope.runTest {
val blueprintId by collectLastValue(underTest.blueprintId)
- kosmos.shadeRepository.setShadeMode(ShadeMode.Split)
+ kosmos.shadeRepository.setShadeLayoutWide(true)
configurationRepository.onConfigurationChange()
runCurrent()
@@ -112,7 +111,7 @@ class KeyguardBlueprintInteractorTest : SysuiTestCase() {
fun testDoesNotApplySplitShadeBlueprint() {
testScope.runTest {
val blueprintId by collectLastValue(underTest.blueprintId)
- kosmos.shadeRepository.setShadeMode(ShadeMode.Split)
+ kosmos.shadeRepository.setShadeLayoutWide(true)
clockRepository.setCurrentClock(clockController)
configurationRepository.onConfigurationChange()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt
index 974e3bb133d8..8bc0a6040e12 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt
@@ -31,7 +31,6 @@ import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.kosmos.testScope
import com.android.systemui.scene.data.repository.Idle
import com.android.systemui.scene.data.repository.setSceneTransition
-import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
@@ -75,7 +74,6 @@ class KeyguardDismissActionInteractorTest : SysuiTestCase() {
transitionInteractor = kosmos.keyguardTransitionInteractor,
dismissInteractor = dismissInteractorWithDependencies.interactor,
applicationScope = testScope.backgroundScope,
- sceneInteractor = kosmos.sceneInteractor,
)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
index 824132adc0d5..3b0f623d1453 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
@@ -1314,6 +1314,7 @@ class KeyguardTransitionScenariosTest(flags: FlagsParameterization?) : SysuiTest
}
@Test
+ @DisableSceneContainer
fun occludedToPrimaryBouncer() =
testScope.runTest {
// GIVEN a prior transition has run to OCCLUDED
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardWakeDirectlyToGoneInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardWakeDirectlyToGoneInteractorTest.kt
index 22181f8fa568..7e249e8c179d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardWakeDirectlyToGoneInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardWakeDirectlyToGoneInteractorTest.kt
@@ -24,10 +24,12 @@ import android.content.Intent
import android.content.mockedContext
import android.os.PowerManager
import android.os.UserHandle
+import android.platform.test.annotations.EnableFlags
import android.provider.Settings
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.widget.lockPatternUtils
+import com.android.systemui.Flags
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectValues
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
@@ -78,6 +80,7 @@ class KeyguardWakeDirectlyToGoneInteractorTest : SysuiTestCase() {
private val transitionRepository = kosmos.fakeKeyguardTransitionRepository
@Test
+ @EnableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR)
fun testCanWakeDirectlyToGone_keyguardServiceEnabledThenDisabled() =
testScope.runTest {
val canWake by collectValues(underTest.canWakeDirectlyToGone)
@@ -114,6 +117,7 @@ class KeyguardWakeDirectlyToGoneInteractorTest : SysuiTestCase() {
}
@Test
+ @EnableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR)
fun testCanWakeDirectlyToGone_lockscreenDisabledThenEnabled() =
testScope.runTest {
val canWake by collectValues(underTest.canWakeDirectlyToGone)
@@ -178,6 +182,7 @@ class KeyguardWakeDirectlyToGoneInteractorTest : SysuiTestCase() {
}
@Test
+ @EnableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR)
fun testCanWakeDirectlyToGone_wakeAndUnlock() =
testScope.runTest {
val canWake by collectValues(underTest.canWakeDirectlyToGone)
@@ -201,6 +206,7 @@ class KeyguardWakeDirectlyToGoneInteractorTest : SysuiTestCase() {
}
@Test
+ @EnableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR)
fun testCanWakeDirectlyToGone_andSetsAlarm_ifPowerButtonDoesNotLockImmediately() =
testScope.runTest {
val canWake by collectValues(underTest.canWakeDirectlyToGone)
@@ -224,6 +230,7 @@ class KeyguardWakeDirectlyToGoneInteractorTest : SysuiTestCase() {
}
@Test
+ @EnableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR)
fun testSetsCanIgnoreAuth_andSetsAlarm_whenTimingOut() =
testScope.runTest {
val canWake by collectValues(underTest.canWakeDirectlyToGone)
@@ -267,6 +274,7 @@ class KeyguardWakeDirectlyToGoneInteractorTest : SysuiTestCase() {
}
@Test
+ @EnableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR)
fun testCancelsFirstAlarm_onWake_withSecondAlarmSet() =
testScope.runTest {
val canWake by collectValues(underTest.canWakeDirectlyToGone)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSectionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSectionTest.kt
index 4a39a9b2e801..6e381caf5124 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSectionTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSectionTest.kt
@@ -39,7 +39,6 @@ import com.android.systemui.kosmos.Kosmos
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.shared.model.ShadeMode
import com.android.systemui.statusbar.notification.stack.domain.interactor.notificationsKeyguardInteractor
import com.android.systemui.statusbar.policy.fakeConfigurationController
import com.android.systemui.statusbar.ui.fakeSystemBarUtilsProxy
@@ -48,6 +47,7 @@ import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.advanceUntilIdle
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -57,6 +57,7 @@ import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.anyString
import org.mockito.MockitoAnnotations
+@OptIn(ExperimentalCoroutinesApi::class)
@RunWith(AndroidJUnit4::class)
@SmallTest
class ClockSectionTest : SysuiTestCase() {
@@ -127,7 +128,7 @@ class ClockSectionTest : SysuiTestCase() {
fun testApplyDefaultConstraints_LargeClock_SplitShade() =
kosmos.testScope.runTest {
with(kosmos) {
- shadeRepository.setShadeMode(ShadeMode.Split)
+ shadeRepository.setShadeLayoutWide(true)
keyguardClockInteractor.setClockSize(ClockSize.LARGE)
advanceUntilIdle()
}
@@ -143,11 +144,11 @@ class ClockSectionTest : SysuiTestCase() {
fun testApplyDefaultConstraints_LargeClock_NonSplitShade() =
kosmos.testScope.runTest {
with(kosmos) {
- val collectedShadeMode by collectLastValue(shadeRepository.shadeMode)
+ val isShadeLayoutWide by collectLastValue(shadeRepository.isShadeLayoutWide)
val isLargeClockVisible by
collectLastValue(keyguardClockViewModel.isLargeClockVisible)
- shadeRepository.setShadeMode(ShadeMode.Single)
+ shadeRepository.setShadeLayoutWide(false)
keyguardClockInteractor.setClockSize(ClockSize.LARGE)
fakeKeyguardRepository.setClockShouldBeCentered(true)
notificationsKeyguardInteractor.setNotificationsFullyHidden(true)
@@ -168,11 +169,11 @@ class ClockSectionTest : SysuiTestCase() {
kosmos.testScope.runTest {
with(kosmos) {
DIMENSION_BY_IDENTIFIER = listOf() // Remove Smartspace from mock
- val collectedShadeMode by collectLastValue(shadeRepository.shadeMode)
+ val isShadeLayoutWide by collectLastValue(shadeRepository.isShadeLayoutWide)
val isLargeClockVisible by
collectLastValue(keyguardClockViewModel.isLargeClockVisible)
- shadeRepository.setShadeMode(ShadeMode.Split)
+ shadeRepository.setShadeLayoutWide(true)
keyguardClockInteractor.setClockSize(ClockSize.LARGE)
fakeKeyguardRepository.setClockShouldBeCentered(true)
notificationsKeyguardInteractor.setNotificationsFullyHidden(true)
@@ -193,11 +194,11 @@ class ClockSectionTest : SysuiTestCase() {
kosmos.testScope.runTest {
with(kosmos) {
DIMENSION_BY_IDENTIFIER = listOf() // Remove Smartspace from mock
- val collectedShadeMode by collectLastValue(shadeRepository.shadeMode)
+ val isShadeLayoutWide by collectLastValue(shadeRepository.isShadeLayoutWide)
val isLargeClockVisible by
collectLastValue(keyguardClockViewModel.isLargeClockVisible)
- shadeRepository.setShadeMode(ShadeMode.Single)
+ shadeRepository.setShadeLayoutWide(false)
keyguardClockInteractor.setClockSize(ClockSize.LARGE)
fakeKeyguardRepository.setClockShouldBeCentered(true)
notificationsKeyguardInteractor.setNotificationsFullyHidden(true)
@@ -217,11 +218,11 @@ class ClockSectionTest : SysuiTestCase() {
fun testApplyDefaultConstraints_SmallClock_SplitShade() =
kosmos.testScope.runTest {
with(kosmos) {
- val collectedShadeMode by collectLastValue(shadeRepository.shadeMode)
+ val isShadeLayoutWide by collectLastValue(shadeRepository.isShadeLayoutWide)
val isLargeClockVisible by
collectLastValue(keyguardClockViewModel.isLargeClockVisible)
- shadeRepository.setShadeMode(ShadeMode.Split)
+ shadeRepository.setShadeLayoutWide(true)
keyguardClockInteractor.setClockSize(ClockSize.SMALL)
fakeKeyguardRepository.setClockShouldBeCentered(true)
notificationsKeyguardInteractor.setNotificationsFullyHidden(true)
@@ -241,11 +242,11 @@ class ClockSectionTest : SysuiTestCase() {
fun testApplyDefaultConstraints_SmallClock_NonSplitShade() =
kosmos.testScope.runTest {
with(kosmos) {
- val collectedShadeMode by collectLastValue(shadeRepository.shadeMode)
+ val isShadeLayoutWide by collectLastValue(shadeRepository.isShadeLayoutWide)
val isLargeClockVisible by
collectLastValue(keyguardClockViewModel.isLargeClockVisible)
- shadeRepository.setShadeMode(ShadeMode.Single)
+ shadeRepository.setShadeLayoutWide(false)
keyguardClockInteractor.setClockSize(ClockSize.SMALL)
fakeKeyguardRepository.setClockShouldBeCentered(true)
notificationsKeyguardInteractor.setNotificationsFullyHidden(true)
@@ -334,7 +335,7 @@ class ClockSectionTest : SysuiTestCase() {
}
companion object {
- private val SMART_SPACE_DATE_WEATHER_HEIGHT = 10
- private val ENHANCED_SMART_SPACE_HEIGHT = 11
+ private const val SMART_SPACE_DATE_WEATHER_HEIGHT = 10
+ private const val ENHANCED_SMART_SPACE_HEIGHT = 11
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelTest.kt
index 40663ceb2ad2..17e1b53a3ba9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelTest.kt
@@ -38,7 +38,6 @@ import com.android.systemui.plugins.clocks.ClockFaceConfig
import com.android.systemui.plugins.clocks.ClockFaceController
import com.android.systemui.res.R
import com.android.systemui.shade.data.repository.shadeRepository
-import com.android.systemui.shade.shared.model.ShadeMode
import com.android.systemui.statusbar.ui.fakeSystemBarUtilsProxy
import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.whenever
@@ -88,7 +87,7 @@ class KeyguardClockViewModelTest(flags: FlagsParameterization) : SysuiTestCase()
val currentClockLayout by collectLastValue(underTest.currentClockLayout)
with(kosmos) {
- shadeRepository.setShadeMode(ShadeMode.Split)
+ shadeRepository.setShadeLayoutWide(true)
keyguardRepository.setClockShouldBeCentered(true)
keyguardClockRepository.setClockSize(ClockSize.LARGE)
}
@@ -103,7 +102,7 @@ class KeyguardClockViewModelTest(flags: FlagsParameterization) : SysuiTestCase()
val currentClockLayout by collectLastValue(underTest.currentClockLayout)
with(kosmos) {
- shadeRepository.setShadeMode(ShadeMode.Split)
+ shadeRepository.setShadeLayoutWide(true)
keyguardRepository.setClockShouldBeCentered(false)
keyguardClockRepository.setClockSize(ClockSize.LARGE)
}
@@ -118,7 +117,7 @@ class KeyguardClockViewModelTest(flags: FlagsParameterization) : SysuiTestCase()
val currentClockLayout by collectLastValue(underTest.currentClockLayout)
with(kosmos) {
- shadeRepository.setShadeMode(ShadeMode.Split)
+ shadeRepository.setShadeLayoutWide(true)
keyguardRepository.setClockShouldBeCentered(false)
keyguardClockRepository.setClockSize(ClockSize.SMALL)
}
@@ -133,7 +132,7 @@ class KeyguardClockViewModelTest(flags: FlagsParameterization) : SysuiTestCase()
val currentClockLayout by collectLastValue(underTest.currentClockLayout)
with(kosmos) {
- shadeRepository.setShadeMode(ShadeMode.Single)
+ shadeRepository.setShadeLayoutWide(false)
keyguardClockRepository.setClockSize(ClockSize.SMALL)
}
@@ -146,7 +145,7 @@ class KeyguardClockViewModelTest(flags: FlagsParameterization) : SysuiTestCase()
val currentClockLayout by collectLastValue(underTest.currentClockLayout)
with(kosmos) {
- shadeRepository.setShadeMode(ShadeMode.Single)
+ shadeRepository.setShadeLayoutWide(false)
keyguardClockRepository.setClockSize(ClockSize.LARGE)
}
@@ -234,7 +233,7 @@ class KeyguardClockViewModelTest(flags: FlagsParameterization) : SysuiTestCase()
fun testSmallClockTop_splitShade_composeLockscreenOn() =
testScope.runTest {
with(kosmos) {
- shadeRepository.setShadeMode(ShadeMode.Split)
+ shadeRepository.setShadeLayoutWide(true)
fakeSystemBarUtilsProxy.fakeKeyguardStatusBarHeight = KEYGUARD_STATUS_BAR_HEIGHT
}
@@ -249,7 +248,7 @@ class KeyguardClockViewModelTest(flags: FlagsParameterization) : SysuiTestCase()
fun testSmallClockTop_splitShade_composeLockscreenOff() =
testScope.runTest {
with(kosmos) {
- shadeRepository.setShadeMode(ShadeMode.Split)
+ shadeRepository.setShadeLayoutWide(true)
fakeSystemBarUtilsProxy.fakeKeyguardStatusBarHeight = KEYGUARD_STATUS_BAR_HEIGHT
}
@@ -262,7 +261,7 @@ class KeyguardClockViewModelTest(flags: FlagsParameterization) : SysuiTestCase()
fun testSmallClockTop_nonSplitShade_composeLockscreenOn() =
testScope.runTest {
with(kosmos) {
- shadeRepository.setShadeMode(ShadeMode.Single)
+ shadeRepository.setShadeLayoutWide(false)
fakeSystemBarUtilsProxy.fakeKeyguardStatusBarHeight = KEYGUARD_STATUS_BAR_HEIGHT
}
@@ -275,7 +274,7 @@ class KeyguardClockViewModelTest(flags: FlagsParameterization) : SysuiTestCase()
fun testSmallClockTop_nonSplitShade_composeLockscreenOff() =
testScope.runTest {
with(kosmos) {
- shadeRepository.setShadeMode(ShadeMode.Single)
+ shadeRepository.setShadeLayoutWide(false)
fakeSystemBarUtilsProxy.fakeKeyguardStatusBarHeight = KEYGUARD_STATUS_BAR_HEIGHT
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilterImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilterImplTest.kt
index 850e2e014c57..3705909cbc2b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilterImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilterImplTest.kt
@@ -31,6 +31,7 @@ import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.media.controls.MediaTestUtils
import com.android.systemui.media.controls.data.repository.MediaFilterRepository
import com.android.systemui.media.controls.data.repository.mediaFilterRepository
+import com.android.systemui.media.controls.shared.mockMediaLogger
import com.android.systemui.media.controls.shared.model.EXTRA_KEY_TRIGGER_RESUME
import com.android.systemui.media.controls.shared.model.MediaCommonModel
import com.android.systemui.media.controls.shared.model.MediaData
@@ -114,7 +115,7 @@ class MediaDataFilterImplTest : SysuiTestCase() {
mediaSmartspaceLogger = mockMediaSmartspaceLogger
mediaFilterRepository
}
- private val mediaLoadingLogger = kosmos.mockMediaLoadingLogger
+ private val mediaLogger = kosmos.mockMediaLogger
@Before
fun setup() {
@@ -133,7 +134,7 @@ class MediaDataFilterImplTest : SysuiTestCase() {
logger,
mediaFlags,
repository,
- mediaLoadingLogger,
+ mediaLogger,
)
mediaDataFilter.mediaDataProcessor = mediaDataProcessor
mediaDataFilter.addListener(listener)
@@ -194,7 +195,7 @@ class MediaDataFilterImplTest : SysuiTestCase() {
verify(listener)
.onMediaDataLoaded(eq(KEY), eq(null), eq(dataMain), eq(true), eq(0), eq(false))
- verify(mediaLoadingLogger)
+ verify(mediaLogger)
.logMediaLoaded(eq(dataMain.instanceId), eq(dataMain.active), anyString())
assertThat(currentMedia).containsExactly(mediaCommonModel)
}
@@ -210,7 +211,7 @@ class MediaDataFilterImplTest : SysuiTestCase() {
verify(listener, never())
.onMediaDataLoaded(any(), any(), any(), anyBoolean(), anyInt(), anyBoolean())
- verify(mediaLoadingLogger, never()).logMediaLoaded(any(), anyBoolean(), anyString())
+ verify(mediaLogger, never()).logMediaLoaded(any(), anyBoolean(), anyString())
assertThat(currentMedia).doesNotContain(mediaCommonModel)
}
@@ -224,14 +225,14 @@ class MediaDataFilterImplTest : SysuiTestCase() {
// GIVEN a media was removed for main user
mediaDataFilter.onMediaDataLoaded(KEY, null, dataMain)
- verify(mediaLoadingLogger)
+ verify(mediaLogger)
.logMediaLoaded(eq(dataMain.instanceId), eq(dataMain.active), anyString())
assertThat(currentMedia).containsExactly(mediaCommonModel)
mediaDataFilter.onMediaDataRemoved(KEY, false)
verify(listener).onMediaDataRemoved(eq(KEY), eq(false))
- verify(mediaLoadingLogger).logMediaRemoved(eq(dataMain.instanceId), anyString())
+ verify(mediaLogger).logMediaRemoved(eq(dataMain.instanceId), anyString())
assertThat(currentMedia).doesNotContain(mediaCommonModel)
}
@@ -245,8 +246,7 @@ class MediaDataFilterImplTest : SysuiTestCase() {
mediaDataFilter.onMediaDataRemoved(KEY, false)
verify(listener, never()).onMediaDataRemoved(eq(KEY), eq(false))
- verify(mediaLoadingLogger, never())
- .logMediaRemoved(eq(dataGuest.instanceId), anyString())
+ verify(mediaLogger, never()).logMediaRemoved(eq(dataGuest.instanceId), anyString())
assertThat(currentMedia).isEmpty()
}
@@ -259,7 +259,7 @@ class MediaDataFilterImplTest : SysuiTestCase() {
// GIVEN that we have a media loaded for main user
mediaDataFilter.onMediaDataLoaded(KEY, null, dataMain)
- verify(mediaLoadingLogger)
+ verify(mediaLogger)
.logMediaLoaded(eq(dataMain.instanceId), eq(dataMain.active), anyString())
assertThat(currentMedia).containsExactly(MediaCommonModel.MediaControl(mediaLoaded))
@@ -268,7 +268,7 @@ class MediaDataFilterImplTest : SysuiTestCase() {
// THEN we should remove the main user's media
verify(listener).onMediaDataRemoved(eq(KEY), eq(false))
- verify(mediaLoadingLogger).logMediaRemoved(eq(dataMain.instanceId), anyString())
+ verify(mediaLogger).logMediaRemoved(eq(dataMain.instanceId), anyString())
assertThat(currentMedia).isEmpty()
}
@@ -289,10 +289,10 @@ class MediaDataFilterImplTest : SysuiTestCase() {
// THEN we should add back the guest user media
verify(listener)
.onMediaDataLoaded(eq(KEY_ALT), eq(null), eq(dataGuest), eq(true), eq(0), eq(false))
- verify(mediaLoadingLogger)
+ verify(mediaLogger)
.logMediaLoaded(eq(dataGuest.instanceId), eq(dataGuest.active), anyString())
- reset(mediaLoadingLogger)
+ reset(mediaLogger)
// but not the main user's
verify(listener, never())
@@ -304,7 +304,7 @@ class MediaDataFilterImplTest : SysuiTestCase() {
anyInt(),
anyBoolean()
)
- verify(mediaLoadingLogger, never())
+ verify(mediaLogger, never())
.logMediaLoaded(eq(dataMain.instanceId), anyBoolean(), anyString())
assertThat(currentMedia)
.containsExactly(MediaCommonModel.MediaControl(guestLoadedStatesModel))
@@ -327,7 +327,7 @@ class MediaDataFilterImplTest : SysuiTestCase() {
val mediaLoadedStatesModel = MediaDataLoadingModel.Loaded(dataMain.instanceId)
// THEN we should remove the private profile media
verify(listener).onMediaDataRemoved(eq(KEY_ALT), eq(false))
- verify(mediaLoadingLogger).logMediaRemoved(eq(dataGuest.instanceId), anyString())
+ verify(mediaLogger).logMediaRemoved(eq(dataGuest.instanceId), anyString())
assertThat(currentMedia)
.containsExactly(MediaCommonModel.MediaControl(mediaLoadedStatesModel))
}
@@ -591,8 +591,7 @@ class MediaDataFilterImplTest : SysuiTestCase() {
assertThat(hasActiveMedia(selectedUserEntries)).isFalse()
verify(listener)
.onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData), eq(true))
- verify(mediaLoadingLogger)
- .logRecommendationLoaded(eq(SMARTSPACE_KEY), eq(true), anyString())
+ verify(mediaLogger).logRecommendationLoaded(eq(SMARTSPACE_KEY), eq(true), anyString())
verify(logger).logRecommendationAdded(SMARTSPACE_PACKAGE, SMARTSPACE_INSTANCE_ID)
verify(logger, never()).logRecommendationActivated(any(), any(), any())
}
@@ -622,9 +621,8 @@ class MediaDataFilterImplTest : SysuiTestCase() {
verify(listener, never())
.onMediaDataLoaded(any(), any(), any(), anyBoolean(), anyInt(), anyBoolean())
verify(listener, never()).onSmartspaceMediaDataLoaded(any(), any(), anyBoolean())
- verify(mediaLoadingLogger, never()).logMediaLoaded(any(), anyBoolean(), anyString())
- verify(mediaLoadingLogger, never())
- .logRecommendationLoaded(any(), anyBoolean(), anyString())
+ verify(mediaLogger, never()).logMediaLoaded(any(), anyBoolean(), anyString())
+ verify(mediaLogger, never()).logRecommendationLoaded(any(), anyBoolean(), anyString())
verify(logger, never()).logRecommendationAdded(any(), any())
verify(logger, never()).logRecommendationActivated(any(), any(), any())
}
@@ -662,8 +660,7 @@ class MediaDataFilterImplTest : SysuiTestCase() {
assertThat(hasActiveMedia(selectedUserEntries)).isFalse()
verify(listener)
.onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData), eq(true))
- verify(mediaLoadingLogger)
- .logRecommendationLoaded(eq(SMARTSPACE_KEY), eq(true), anyString())
+ verify(mediaLogger).logRecommendationLoaded(eq(SMARTSPACE_KEY), eq(true), anyString())
verify(logger).logRecommendationAdded(SMARTSPACE_PACKAGE, SMARTSPACE_INSTANCE_ID)
verify(logger, never()).logRecommendationActivated(any(), any(), any())
}
@@ -698,8 +695,7 @@ class MediaDataFilterImplTest : SysuiTestCase() {
.isFalse()
assertThat(hasActiveMedia(selectedUserEntries)).isFalse()
verify(listener, never()).onSmartspaceMediaDataLoaded(any(), any(), anyBoolean())
- verify(mediaLoadingLogger, never())
- .logRecommendationLoaded(any(), anyBoolean(), anyString())
+ verify(mediaLogger, never()).logRecommendationLoaded(any(), anyBoolean(), anyString())
verify(logger, never()).logRecommendationAdded(any(), any())
verify(logger, never()).logRecommendationActivated(any(), any(), any())
}
@@ -727,10 +723,10 @@ class MediaDataFilterImplTest : SysuiTestCase() {
assertThat(currentMedia).containsExactly(controlCommonModel)
verify(listener)
.onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent), eq(true), eq(0), eq(false))
- verify(mediaLoadingLogger)
+ verify(mediaLogger)
.logMediaLoaded(eq(dataCurrent.instanceId), eq(dataCurrent.active), anyString())
- reset(mediaLoadingLogger)
+ reset(mediaLogger)
// AND we get a smartspace signal
mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
@@ -749,10 +745,9 @@ class MediaDataFilterImplTest : SysuiTestCase() {
verify(listener, never())
.onMediaDataLoaded(eq(KEY), eq(KEY), any(), anyBoolean(), anyInt(), anyBoolean())
verify(listener, never()).onSmartspaceMediaDataLoaded(any(), any(), anyBoolean())
- verify(mediaLoadingLogger, never())
+ verify(mediaLogger, never())
.logMediaLoaded(eq(dataCurrent.instanceId), anyBoolean(), anyString())
- verify(mediaLoadingLogger, never())
- .logRecommendationLoaded(any(), anyBoolean(), anyString())
+ verify(mediaLogger, never()).logRecommendationLoaded(any(), anyBoolean(), anyString())
verify(logger, never()).logRecommendationAdded(any(), any())
verify(logger, never()).logRecommendationActivated(any(), any(), any())
}
@@ -775,7 +770,7 @@ class MediaDataFilterImplTest : SysuiTestCase() {
assertThat(currentMedia).containsExactly(controlCommonModel)
verify(listener)
.onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent), eq(true), eq(0), eq(false))
- verify(mediaLoadingLogger)
+ verify(mediaLogger)
.logMediaLoaded(eq(dataCurrent.instanceId), eq(dataCurrent.active), anyString())
// AND we get a smartspace signal
@@ -810,7 +805,7 @@ class MediaDataFilterImplTest : SysuiTestCase() {
eq(100),
eq(true)
)
- verify(mediaLoadingLogger)
+ verify(mediaLogger)
.logMediaLoaded(
eq(dataCurrentAndActive.instanceId),
eq(dataCurrentAndActive.active),
@@ -818,8 +813,7 @@ class MediaDataFilterImplTest : SysuiTestCase() {
)
// Smartspace update shouldn't be propagated for the empty rec list.
verify(listener, never()).onSmartspaceMediaDataLoaded(any(), any(), anyBoolean())
- verify(mediaLoadingLogger, never())
- .logRecommendationLoaded(any(), anyBoolean(), anyString())
+ verify(mediaLogger, never()).logRecommendationLoaded(any(), anyBoolean(), anyString())
verify(logger, never()).logRecommendationAdded(any(), any())
verify(logger).logRecommendationActivated(eq(APP_UID), eq(PACKAGE), eq(INSTANCE_ID))
}
@@ -846,7 +840,7 @@ class MediaDataFilterImplTest : SysuiTestCase() {
assertThat(currentMedia).containsExactly(controlCommonModel)
verify(listener)
.onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent), eq(true), eq(0), eq(false))
- verify(mediaLoadingLogger)
+ verify(mediaLogger)
.logMediaLoaded(eq(dataCurrent.instanceId), eq(dataCurrent.active), anyString())
// AND we get a smartspace signal
@@ -865,7 +859,7 @@ class MediaDataFilterImplTest : SysuiTestCase() {
eq(100),
eq(true)
)
- verify(mediaLoadingLogger)
+ verify(mediaLogger)
.logMediaLoaded(
eq(dataCurrentAndActive.instanceId),
eq(dataCurrentAndActive.active),
@@ -890,8 +884,7 @@ class MediaDataFilterImplTest : SysuiTestCase() {
assertThat(currentMedia).containsExactly(controlCommonModel, recsCommonModel)
verify(listener)
.onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData), eq(false))
- verify(mediaLoadingLogger)
- .logRecommendationLoaded(eq(SMARTSPACE_KEY), eq(true), anyString())
+ verify(mediaLogger).logRecommendationLoaded(eq(SMARTSPACE_KEY), eq(true), anyString())
verify(logger).logRecommendationAdded(SMARTSPACE_PACKAGE, SMARTSPACE_INSTANCE_ID)
verify(logger).logRecommendationActivated(eq(APP_UID), eq(PACKAGE), eq(INSTANCE_ID))
}
@@ -908,8 +901,7 @@ class MediaDataFilterImplTest : SysuiTestCase() {
mediaDataFilter.onSmartspaceMediaDataRemoved(SMARTSPACE_KEY)
verify(listener).onSmartspaceMediaDataRemoved(SMARTSPACE_KEY)
- verify(mediaLoadingLogger)
- .logRecommendationRemoved(eq(SMARTSPACE_KEY), eq(true), anyString())
+ verify(mediaLogger).logRecommendationRemoved(eq(SMARTSPACE_KEY), eq(true), anyString())
assertThat(currentMedia).isEmpty()
assertThat(
hasActiveMediaOrRecommendation(
@@ -941,7 +933,7 @@ class MediaDataFilterImplTest : SysuiTestCase() {
assertThat(currentMedia).containsExactly(controlCommonModel)
verify(listener)
.onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent), eq(true), eq(0), eq(false))
- verify(mediaLoadingLogger)
+ verify(mediaLogger)
.logMediaLoaded(eq(dataCurrent.instanceId), eq(dataCurrent.active), anyString())
runCurrent()
@@ -958,7 +950,7 @@ class MediaDataFilterImplTest : SysuiTestCase() {
eq(100),
eq(true)
)
- verify(mediaLoadingLogger)
+ verify(mediaLogger)
.logMediaLoaded(
eq(dataCurrentAndActive.instanceId),
eq(dataCurrentAndActive.active),
@@ -968,8 +960,7 @@ class MediaDataFilterImplTest : SysuiTestCase() {
mediaDataFilter.onSmartspaceMediaDataRemoved(SMARTSPACE_KEY)
verify(listener).onSmartspaceMediaDataRemoved(SMARTSPACE_KEY)
- verify(mediaLoadingLogger)
- .logRecommendationRemoved(eq(SMARTSPACE_KEY), eq(true), anyString())
+ verify(mediaLogger).logRecommendationRemoved(eq(SMARTSPACE_KEY), eq(true), anyString())
assertThat(currentMedia).containsExactly(controlCommonModel)
assertThat(
hasActiveMediaOrRecommendation(
@@ -1000,8 +991,7 @@ class MediaDataFilterImplTest : SysuiTestCase() {
verify(listener)
.onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData), eq(false))
- verify(mediaLoadingLogger)
- .logRecommendationLoaded(eq(SMARTSPACE_KEY), eq(false), anyString())
+ verify(mediaLogger).logRecommendationLoaded(eq(SMARTSPACE_KEY), eq(false), anyString())
assertThat(currentMedia).containsExactly(recsCommonModel)
assertThat(
hasActiveMediaOrRecommendation(
@@ -1042,11 +1032,11 @@ class MediaDataFilterImplTest : SysuiTestCase() {
verify(listener)
.onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent), eq(true), eq(0), eq(false))
- verify(mediaLoadingLogger)
+ verify(mediaLogger)
.logMediaLoaded(eq(dataCurrent.instanceId), eq(dataCurrent.active), anyString())
assertThat(currentMedia).containsExactly(controlCommonModel)
- reset(mediaLoadingLogger)
+ reset(mediaLogger)
// And an inactive recommendation is loaded
mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
@@ -1054,11 +1044,10 @@ class MediaDataFilterImplTest : SysuiTestCase() {
// Smartspace is loaded but the media stays inactive
verify(listener)
.onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData), eq(false))
- verify(mediaLoadingLogger)
- .logRecommendationLoaded(eq(SMARTSPACE_KEY), eq(false), anyString())
+ verify(mediaLogger).logRecommendationLoaded(eq(SMARTSPACE_KEY), eq(false), anyString())
verify(listener, never())
.onMediaDataLoaded(any(), any(), any(), anyBoolean(), anyInt(), anyBoolean())
- verify(mediaLoadingLogger, never()).logMediaLoaded(any(), anyBoolean(), anyString())
+ verify(mediaLogger, never()).logMediaLoaded(any(), anyBoolean(), anyString())
assertThat(currentMedia).containsExactly(controlCommonModel, recsCommonModel)
assertThat(
hasActiveMediaOrRecommendation(
@@ -1127,7 +1116,7 @@ class MediaDataFilterImplTest : SysuiTestCase() {
verify(listener)
.onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent), eq(true), eq(0), eq(false))
- verify(mediaLoadingLogger)
+ verify(mediaLogger)
.logMediaLoaded(eq(dataCurrent.instanceId), eq(dataCurrent.active), anyString())
assertThat(currentMedia).containsExactly(controlCommonModel)
@@ -1156,7 +1145,7 @@ class MediaDataFilterImplTest : SysuiTestCase() {
eq(100),
eq(true)
)
- verify(mediaLoadingLogger)
+ verify(mediaLogger)
.logMediaLoaded(
eq(dataCurrentAndActive.instanceId),
eq(dataCurrentAndActive.active),
@@ -1174,8 +1163,7 @@ class MediaDataFilterImplTest : SysuiTestCase() {
// And update the smartspace data state, but not prioritized
verify(listener)
.onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData), eq(false))
- verify(mediaLoadingLogger)
- .logRecommendationLoaded(eq(SMARTSPACE_KEY), eq(true), anyString())
+ verify(mediaLogger).logRecommendationLoaded(eq(SMARTSPACE_KEY), eq(true), anyString())
}
@Test
@@ -1199,11 +1187,11 @@ class MediaDataFilterImplTest : SysuiTestCase() {
verify(listener)
.onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent), eq(true), eq(0), eq(false))
- verify(mediaLoadingLogger)
+ verify(mediaLogger)
.logMediaLoaded(eq(dataCurrent.instanceId), eq(dataCurrent.active), anyString())
assertThat(currentMedia).containsExactly(controlCommonModel)
- reset(mediaLoadingLogger)
+ reset(mediaLogger)
// AND we get a smartspace signal with extra to not trigger resume
val extras = Bundle().apply { putBoolean(EXTRA_KEY_TRIGGER_RESUME, false) }
@@ -1213,13 +1201,12 @@ class MediaDataFilterImplTest : SysuiTestCase() {
// THEN listeners are not updated to show media
verify(listener, never())
.onMediaDataLoaded(eq(KEY), eq(KEY), any(), eq(true), eq(100), eq(true))
- verify(mediaLoadingLogger, never())
+ verify(mediaLogger, never())
.logMediaLoaded(eq(dataCurrent.instanceId), anyBoolean(), anyString())
// But the smartspace update is still propagated
verify(listener)
.onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData), eq(false))
- verify(mediaLoadingLogger)
- .logRecommendationLoaded(eq(SMARTSPACE_KEY), eq(true), anyString())
+ verify(mediaLogger).logRecommendationLoaded(eq(SMARTSPACE_KEY), eq(true), anyString())
assertThat(currentMedia).containsExactly(controlCommonModel, recsCommonModel)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/views/NavigationBarTransitionsTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/views/NavigationBarTransitionsTest.java
index b0265c07363f..3621ab975daf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/views/NavigationBarTransitionsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/views/NavigationBarTransitionsTest.java
@@ -103,7 +103,7 @@ public class NavigationBarTransitionsTest extends SysuiTestCase {
public void setIsLightsOut_AutoDim() {
mTransitions.setAutoDim(true);
- assertTrue(mTransitions.isLightsOut(BarTransitions.MODE_LIGHTS_OUT_TRANSPARENT));
+ assertTrue(mTransitions.isLightsOut(BarTransitions.MODE_OPAQUE));
assertTrue(mTransitions.isLightsOut(BarTransitions.MODE_LIGHTS_OUT));
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java
index 16a022f720ae..8681123d0c2b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java
@@ -276,8 +276,8 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mLauncherApps = mock(LauncherApps.class);
- mManager = new PeopleSpaceWidgetManager(mContext, mAppWidgetManager, mIPeopleManager,
- mPeopleManager, mLauncherApps, mNotifCollection, mPackageManager,
+ mManager = new PeopleSpaceWidgetManager(mContext, Optional.of(mAppWidgetManager),
+ mIPeopleManager, mPeopleManager, mLauncherApps, mNotifCollection, mPackageManager,
Optional.of(mBubbles), mUserManager, mBackupManager, mINotificationManager,
mNotificationManager, mFakeExecutor, mUserTracker);
mManager.attach(mListenerService);
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 415cc7c99b2c..988769fe6660 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
@@ -471,7 +471,7 @@ class QSTileViewImplTest : SysuiTestCase() {
}
@Test
- fun onPrepareForLaunch_paddingForLaunchAnimationIsConfigured() {
+ fun getPaddingForLaunchAnimation_onLongClickedState_paddingForLaunchAnimationIsConfigured() {
val startingWidth = 100
val startingHeight = 50
val deltaWidth = (QSTileViewImpl.LONG_PRESS_EFFECT_WIDTH_SCALE - 1f) * startingWidth
@@ -480,8 +480,8 @@ class QSTileViewImplTest : SysuiTestCase() {
// GIVEN that long-press effect properties are initialized
tileView.initializeLongPressProperties(startingHeight, startingWidth)
- // WHEN the tile is preparing for the launch animation
- tileView.prepareForLaunch()
+ // WHEN the long-press effect has ended in the long-click state
+ kosmos.qsLongPressEffect.setState(QSLongPressEffect.State.LONG_CLICKED)
// THE animation padding corresponds to the tile's growth due to the effect
val padding = tileView.getPaddingForLaunchAnimation()
@@ -497,6 +497,22 @@ class QSTileViewImplTest : SysuiTestCase() {
}
@Test
+ fun getPaddingForLaunchAnimation_notInLongClickState_paddingForLaunchAnimationIsEmpty() {
+ val startingWidth = 100
+ val startingHeight = 50
+
+ // GIVEN that long-press effect properties are initialized
+ tileView.initializeLongPressProperties(startingHeight, startingWidth)
+
+ // WHEN the long-press effect has ended in the click state
+ kosmos.qsLongPressEffect.setState(QSLongPressEffect.State.CLICKED)
+
+ // THE animation padding is empty
+ val padding = tileView.getPaddingForLaunchAnimation()
+ assertThat(padding.isEmpty).isTrue()
+ }
+
+ @Test
fun onActivityLaunchAnimationEnd_onFreshTile_longPressPropertiesAreReset() {
// WHEN an activity launch animation ends on a fresh tile
tileView.onActivityLaunchAnimationEnd()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java
index 798e9fb208b7..d6bde27dfb62 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java
@@ -24,6 +24,7 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.os.Handler;
+import android.platform.test.annotations.RequiresFlagsDisabled;
import android.service.quicksettings.Tile;
import android.testing.TestableLooper;
@@ -32,6 +33,7 @@ import androidx.test.filters.SmallTest;
import com.android.internal.R;
import com.android.internal.logging.MetricsLogger;
+import com.android.server.display.feature.flags.Flags;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.plugins.ActivityStarter;
@@ -131,6 +133,7 @@ public class ReduceBrightColorsTileTest extends SysuiTestCase {
}
@Test
+ @RequiresFlagsDisabled(Flags.FLAG_EVEN_DIMMER)
public void testActive_clicked_featureIsActivated() {
when(mReduceBrightColorsController.isReduceBrightColorsActivated()).thenReturn(false);
mTile.refreshState();
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 0b81b5e6de35..8d3a29ac7278 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotExecutorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotExecutorTest.kt
@@ -69,7 +69,7 @@ class TakeScreenshotExecutorTest : SysuiTestCase() {
@Before
fun setUp() {
- whenever(controllerFactory.create(any(), any())).thenReturn(controller)
+ whenever(controllerFactory.create(any())).thenReturn(controller)
whenever(notificationControllerFactory.create(eq(0))).thenReturn(notificationsController0)
whenever(notificationControllerFactory.create(eq(1))).thenReturn(notificationsController1)
}
@@ -83,8 +83,8 @@ class TakeScreenshotExecutorTest : SysuiTestCase() {
val onSaved = { _: Uri? -> }
screenshotExecutor.executeScreenshots(createScreenshotRequest(), onSaved, callback)
- verify(controllerFactory).create(eq(internalDisplay), any())
- verify(controllerFactory, never()).create(eq(externalDisplay), any())
+ verify(controllerFactory).create(eq(internalDisplay))
+ verify(controllerFactory, never()).create(eq(externalDisplay))
val capturer = ArgumentCaptor<ScreenshotData>()
@@ -118,8 +118,8 @@ class TakeScreenshotExecutorTest : SysuiTestCase() {
callback
)
- verify(controllerFactory).create(eq(internalDisplay), any())
- verify(controllerFactory, never()).create(eq(externalDisplay), any())
+ verify(controllerFactory).create(eq(internalDisplay))
+ verify(controllerFactory, never()).create(eq(externalDisplay))
val capturer = ArgumentCaptor<ScreenshotData>()
@@ -151,7 +151,7 @@ class TakeScreenshotExecutorTest : SysuiTestCase() {
@Test
fun executeScreenshots_allowedTypes_allCaptured() =
testScope.runTest {
- whenever(controllerFactory.create(any(), any())).thenReturn(controller)
+ whenever(controllerFactory.create(any())).thenReturn(controller)
setDisplays(
display(TYPE_INTERNAL, id = 0),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsViewModelTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsViewModelTest.java
index baf1357a1ae0..193d29c1d550 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsViewModelTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsViewModelTest.java
@@ -334,13 +334,17 @@ public final class AppClipsViewModelTest extends SysuiTestCase {
}
private void resetPackageManagerMockingForUsingFallbackBacklinks() {
+ ResolveInfo backlinksTaskResolveInfo = createBacklinksTaskResolveInfo();
reset(mPackageManager);
when(mPackageManager.loadItemIcon(any(), any())).thenReturn(FAKE_DRAWABLE);
when(mPackageManager.resolveActivity(any(Intent.class), anyInt()))
- // First the logic queries whether a package has a launcher activity, this should
+ // Firstly, the logic queries whether a package has a launcher activity, this should
// resolve otherwise the logic filters out the task.
- .thenReturn(createBacklinksTaskResolveInfo())
- // Then logic queries with the backlinks intent, this should not resolve for the
+ .thenReturn(backlinksTaskResolveInfo)
+ // Secondly, the logic builds a fallback main launcher intent, this should also
+ // resolve for the fallback intent to build correctly.
+ .thenReturn(backlinksTaskResolveInfo)
+ // Lastly, logic queries with the backlinks intent, this should not resolve for the
// logic to use the fallback intent.
.thenReturn(null);
}
@@ -360,6 +364,8 @@ public final class AppClipsViewModelTest extends SysuiTestCase {
assertThat(actualBacklinksIntent.getPackage()).isEqualTo(BACKLINKS_TASK_PACKAGE_NAME);
assertThat(actualBacklinksIntent.getAction()).isEqualTo(ACTION_MAIN);
assertThat(actualBacklinksIntent.getCategories()).containsExactly(CATEGORY_LAUNCHER);
+ assertThat(actualBacklinksIntent.getComponent()).isEqualTo(
+ new ComponentName(BACKLINKS_TASK_PACKAGE_NAME, BACKLINKS_TASK_APP_NAME));
}
private static ResolveInfo createBacklinksTaskResolveInfo() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt
index 97acc6e53cdf..7d4918a30d9c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt
@@ -19,8 +19,8 @@ package com.android.systemui.shade.data.repository
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest
@@ -28,7 +28,6 @@ import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(AndroidJUnit4::class)
class ShadeRepositoryImplTest : SysuiTestCase() {
@@ -91,37 +90,37 @@ class ShadeRepositoryImplTest : SysuiTestCase() {
@Test
fun updateLegacyShadeTracking() =
testScope.runTest {
- assertThat(underTest.legacyShadeTracking.value).isEqualTo(false)
+ assertThat(underTest.legacyShadeTracking.value).isFalse()
underTest.setLegacyShadeTracking(true)
- assertThat(underTest.legacyShadeTracking.value).isEqualTo(true)
+ assertThat(underTest.legacyShadeTracking.value).isTrue()
}
@Test
fun updateLegacyLockscreenShadeTracking() =
testScope.runTest {
- assertThat(underTest.legacyLockscreenShadeTracking.value).isEqualTo(false)
+ assertThat(underTest.legacyLockscreenShadeTracking.value).isFalse()
underTest.setLegacyLockscreenShadeTracking(true)
- assertThat(underTest.legacyLockscreenShadeTracking.value).isEqualTo(true)
+ assertThat(underTest.legacyLockscreenShadeTracking.value).isTrue()
}
@Test
fun updateLegacyQsTracking() =
testScope.runTest {
- assertThat(underTest.legacyQsTracking.value).isEqualTo(false)
+ assertThat(underTest.legacyQsTracking.value).isFalse()
underTest.setLegacyQsTracking(true)
- assertThat(underTest.legacyQsTracking.value).isEqualTo(true)
+ assertThat(underTest.legacyQsTracking.value).isTrue()
}
@Test
fun updateLegacyExpandedOrAwaitingInputTransfer() =
testScope.runTest {
- assertThat(underTest.legacyExpandedOrAwaitingInputTransfer.value).isEqualTo(false)
+ assertThat(underTest.legacyExpandedOrAwaitingInputTransfer.value).isFalse()
underTest.setLegacyExpandedOrAwaitingInputTransfer(true)
- assertThat(underTest.legacyExpandedOrAwaitingInputTransfer.value).isEqualTo(true)
+ assertThat(underTest.legacyExpandedOrAwaitingInputTransfer.value).isTrue()
}
@Test
@@ -142,36 +141,46 @@ class ShadeRepositoryImplTest : SysuiTestCase() {
@Test
fun updateLegacyIsQsExpanded() =
testScope.runTest {
- assertThat(underTest.legacyIsQsExpanded.value).isEqualTo(false)
+ assertThat(underTest.legacyIsQsExpanded.value).isFalse()
underTest.setLegacyIsQsExpanded(true)
- assertThat(underTest.legacyIsQsExpanded.value).isEqualTo(true)
+ assertThat(underTest.legacyIsQsExpanded.value).isTrue()
}
@Test
fun updateLegacyExpandImmediate() =
testScope.runTest {
- assertThat(underTest.legacyExpandImmediate.value).isEqualTo(false)
+ assertThat(underTest.legacyExpandImmediate.value).isFalse()
underTest.setLegacyExpandImmediate(true)
- assertThat(underTest.legacyExpandImmediate.value).isEqualTo(true)
+ assertThat(underTest.legacyExpandImmediate.value).isTrue()
}
@Test
fun updateLegacyQsFullscreen() =
testScope.runTest {
- assertThat(underTest.legacyQsFullscreen.value).isEqualTo(false)
+ assertThat(underTest.legacyQsFullscreen.value).isFalse()
underTest.setLegacyQsFullscreen(true)
- assertThat(underTest.legacyQsFullscreen.value).isEqualTo(true)
+ assertThat(underTest.legacyQsFullscreen.value).isTrue()
}
@Test
fun updateLegacyIsClosing() =
testScope.runTest {
- assertThat(underTest.legacyIsClosing.value).isEqualTo(false)
+ assertThat(underTest.legacyIsClosing.value).isFalse()
underTest.setLegacyIsClosing(true)
- assertThat(underTest.legacyIsClosing.value).isEqualTo(true)
+ assertThat(underTest.legacyIsClosing.value).isTrue()
+ }
+
+ @Test
+ fun isShadeLayoutWide() =
+ testScope.runTest {
+ val isShadeLayoutWide by collectLastValue(underTest.isShadeLayoutWide)
+ assertThat(isShadeLayoutWide).isFalse()
+
+ underTest.setShadeLayoutWide(true)
+ assertThat(isShadeLayoutWide).isTrue()
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyboardShortcutListSearchTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyboardShortcutListSearchTest.java
index 6985a27a59c8..63e56eeb730f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyboardShortcutListSearchTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyboardShortcutListSearchTest.java
@@ -66,7 +66,9 @@ public class KeyboardShortcutListSearchTest extends SysuiTestCase {
@Before
public void setUp() {
- mKeyboardShortcutListSearch = new KeyboardShortcutListSearch(mContext, mWindowManager);
+ when(mWindowManager.getApplicationLaunchKeyboardShortcuts(anyInt())).thenReturn(
+ new KeyboardShortcutGroup("", Collections.emptyList()));
+ mKeyboardShortcutListSearch = new KeyboardShortcutListSearch(mContext, mWindowManager, -1);
mKeyboardShortcutListSearch.sInstance = mKeyboardShortcutListSearch;
mKeyboardShortcutListSearch.mKeyboardShortcutsBottomSheetDialog = mBottomSheetDialog;
mKeyboardShortcutListSearch.mContext = mContext;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyboardShortcutsTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyboardShortcutsTest.java
index 6ad8b8bc3637..105cf168995c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyboardShortcutsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyboardShortcutsTest.java
@@ -54,6 +54,7 @@ import org.mockito.junit.MockitoRule;
import org.mockito.stubbing.Answer;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
@SmallTest
@@ -71,6 +72,8 @@ public class KeyboardShortcutsTest extends SysuiTestCase {
@Before
public void setUp() {
+ when(mWindowManager.getApplicationLaunchKeyboardShortcuts(anyInt())).thenReturn(
+ new KeyboardShortcutGroup("", Collections.emptyList()));
mKeyboardShortcuts = new KeyboardShortcuts(mContext, mWindowManager);
KeyboardShortcuts.sInstance = mKeyboardShortcuts;
mKeyboardShortcuts.mKeyboardShortcutsDialog = mDialog;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
index e8349b0978e0..ed7383cacd29 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
@@ -1003,21 +1003,6 @@ public class ExpandableNotificationRowTest extends SysuiTestCase {
// THEN
assertThat(row.isExpanded()).isFalse();
}
-
- @Test
- @EnableFlags(ExpandHeadsUpOnInlineReply.FLAG_NAME)
- public void hasUserChangedExpansion_expandPinned_returnTrue() throws Exception {
- // GIVEN
- final ExpandableNotificationRow row = mNotificationTestHelper.createRow();
- row.setPinned(true);
-
- // WHEN
- row.expandNotification();
-
- // THEN
- assertThat(row.hasUserChangedExpansion()).isTrue();
- }
-
@Test
public void onDisappearAnimationFinished_shouldSetFalse_headsUpAnimatingAway()
throws Exception {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
index 285949a41fcd..9eafcdbadfa5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
@@ -495,18 +495,18 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
}
@Test
- public void biometricUnlockStateResetOnTransitionFromGone() {
- mBiometricUnlockController.consumeTransitionStepOnStartedKeyguardState(
+ public void biometricUnlockStateResetOnStartedTransition() {
+ mBiometricUnlockController.consumeFromGoneTransitions(
new TransitionStep(
- KeyguardState.AOD,
KeyguardState.GONE,
+ KeyguardState.AOD,
.1f /* value */,
- TransitionState.STARTED
+ TransitionState.RUNNING
)
);
verify(mBiometricUnlockInteractor, never()).setBiometricUnlockState(anyInt(), any());
- mBiometricUnlockController.consumeTransitionStepOnStartedKeyguardState(
+ mBiometricUnlockController.consumeFromGoneTransitions(
new TransitionStep(
KeyguardState.GONE,
KeyguardState.AOD,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
index 7cb41f119c9a..10d07a0ce004 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
@@ -35,8 +35,8 @@ import android.os.Handler;
import android.os.PowerManager;
import android.provider.Settings;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.SysuiTestCase;
@@ -52,6 +52,7 @@ import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.unfold.FoldAodAnimationController;
import com.android.systemui.unfold.SysUIUnfoldComponent;
+import com.android.systemui.util.settings.FakeSettings;
import org.junit.Assert;
import org.junit.Before;
@@ -130,7 +131,8 @@ public class DozeParametersTest extends SysuiTestCase {
mConfigurationController,
mStatusBarStateController,
mUserTracker,
- mDozeInteractor
+ mDozeInteractor,
+ new FakeSettings()
);
verify(mBatteryController).addCallback(mBatteryStateChangeCallback.capture());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt
index 30e96f10918d..e439aff423b0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt
@@ -738,6 +738,28 @@ class MobileIconInteractorTest : SysuiTestCase() {
assertThat(latest).isInstanceOf(SignalIconModel.Satellite::class.java)
}
+ @EnableFlags(com.android.internal.telephony.flags.Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG)
+ @Test
+ // See b/346904529 for more context
+ fun satBasedIcon_doesNotInflateSignalStrength() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.signalLevelIcon)
+
+ // GIVEN a satellite connection
+ connectionRepository.isNonTerrestrial.value = true
+ // GIVEN this carrier has set INFLATE_SIGNAL_STRENGTH
+ connectionRepository.inflateSignalStrength.value = true
+
+ connectionRepository.primaryLevel.value = 4
+ assertThat(latest!!.level).isEqualTo(4)
+
+ connectionRepository.inflateSignalStrength.value = true
+ connectionRepository.primaryLevel.value = 4
+
+ // Icon level is unaffected
+ assertThat(latest!!.level).isEqualTo(4)
+ }
+
private fun createInteractor(
overrides: MobileIconCarrierIdOverrides = MobileIconCarrierIdOverridesImpl()
) =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt
index cec41557f344..e51092429cd6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt
@@ -862,6 +862,38 @@ class MobileIconViewModelTest : SysuiTestCase() {
assertThat(latest!!.icon.res).isEqualTo(R.drawable.ic_satellite_connected_2)
}
+ @EnableFlags(com.android.internal.telephony.flags.Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG)
+ @Test
+ fun satelliteIcon_ignoresInflateSignalStrength() =
+ testScope.runTest {
+ // Note that this is the exact same test as above, but with inflateSignalStrength set to
+ // true we note that the level is unaffected by inflation
+ repository.inflateSignalStrength.value = true
+ repository.isNonTerrestrial.value = true
+ repository.setAllLevels(0)
+
+ val latest by
+ collectLastValue(underTest.icon.filterIsInstance(SignalIconModel.Satellite::class))
+
+ // Level 0 -> no connection
+ assertThat(latest).isNotNull()
+ assertThat(latest!!.icon.res).isEqualTo(R.drawable.ic_satellite_connected_0)
+
+ // 1-2 -> 1 bar
+ repository.setAllLevels(1)
+ assertThat(latest!!.icon.res).isEqualTo(R.drawable.ic_satellite_connected_1)
+
+ repository.setAllLevels(2)
+ assertThat(latest!!.icon.res).isEqualTo(R.drawable.ic_satellite_connected_1)
+
+ // 3-4 -> 2 bars
+ repository.setAllLevels(3)
+ assertThat(latest!!.icon.res).isEqualTo(R.drawable.ic_satellite_connected_2)
+
+ repository.setAllLevels(4)
+ assertThat(latest!!.icon.res).isEqualTo(R.drawable.ic_satellite_connected_2)
+ }
+
private fun createAndSetViewModel() {
underTest =
MobileIconViewModel(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModelTest.kt
index ef4e7341db74..cc2ef53c6cdb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModelTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.ui.viewmodel
+import android.platform.test.annotations.EnableFlags
import android.platform.test.flag.junit.FlagsParameterization
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -32,6 +33,7 @@ import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.statusbar.domain.interactor.keyguardStatusBarInteractor
import com.android.systemui.statusbar.notification.data.repository.FakeHeadsUpRowRepository
+import com.android.systemui.statusbar.notification.shared.NotificationsHeadsUpRefactor
import com.android.systemui.statusbar.notification.stack.data.repository.headsUpNotificationRepository
import com.android.systemui.statusbar.notification.stack.data.repository.setNotifications
import com.android.systemui.statusbar.notification.stack.domain.interactor.headsUpNotificationInteractor
@@ -126,6 +128,7 @@ class KeyguardStatusBarViewModelTest(flags: FlagsParameterization) : SysuiTestCa
}
@Test
+ @EnableFlags(NotificationsHeadsUpRefactor.FLAG_NAME)
fun isVisible_headsUpStatusBarShown_false() =
testScope.runTest {
val latest by collectLastValue(underTest.isVisible)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/touchpad/tutorial/ui/gesture/BackGestureMonitorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/touchpad/tutorial/ui/gesture/BackGestureMonitorTest.kt
index cf0db7b51676..ce6bc09093bd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/touchpad/tutorial/ui/gesture/BackGestureMonitorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/touchpad/tutorial/ui/gesture/BackGestureMonitorTest.kt
@@ -29,9 +29,11 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
+import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
+@Ignore
@SmallTest
@RunWith(AndroidJUnit4::class)
class BackGestureMonitorTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/touchpad/tutorial/ui/gesture/TouchpadGestureHandlerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/touchpad/tutorial/ui/gesture/TouchpadGestureHandlerTest.kt
index 769f264f0870..f5ef8b005e23 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/touchpad/tutorial/ui/gesture/TouchpadGestureHandlerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/touchpad/tutorial/ui/gesture/TouchpadGestureHandlerTest.kt
@@ -34,9 +34,11 @@ import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.touchpad.tutorial.ui.gesture.TouchpadGesture.BACK
import com.google.common.truth.Truth.assertThat
+import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
+@Ignore
@SmallTest
@RunWith(AndroidJUnit4::class)
class TouchpadGestureHandlerTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/tuner/TunablePaddingTest.java b/packages/SystemUI/tests/src/com/android/systemui/tuner/TunablePaddingTest.java
deleted file mode 100644
index bb7b31b95f5e..000000000000
--- a/packages/SystemUI/tests/src/com/android/systemui/tuner/TunablePaddingTest.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT 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.tuner;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.testing.LeakCheck.Tracker;
-import android.util.DisplayMetrics;
-import android.view.View;
-import android.view.WindowManager;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import com.android.systemui.utils.leaks.LeakCheckedTest;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class TunablePaddingTest extends LeakCheckedTest {
-
- private static final String KEY = "KEY";
- private static final int DEFAULT = 42;
- private View mView;
- private TunablePadding mTunablePadding;
- private TunerService mTunerService;
-
- @Before
- public void setup() {
- injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES);
- mView = mock(View.class);
- when(mView.getContext()).thenReturn(mContext);
-
- mTunerService = mock(TunerService.class);
- mDependency.injectTestDependency(TunablePadding.TunablePaddingService.class,
- new TunablePadding.TunablePaddingService(mTunerService));
- Tracker tracker = mLeakCheck.getTracker("tuner");
- doAnswer(invocation -> {
- tracker.getLeakInfo(invocation.getArguments()[0]).addAllocation(new Throwable());
- return null;
- }).when(mTunerService).addTunable(any(), any());
- doAnswer(invocation -> {
- tracker.getLeakInfo(invocation.getArguments()[0]).clearAllocations();
- return null;
- }).when(mTunerService).removeTunable(any());
- }
-
- @Test
- public void testFlags() {
- mTunablePadding = TunablePadding.addTunablePadding(mView, KEY, DEFAULT,
- TunablePadding.FLAG_START);
- mTunablePadding.onTuningChanged(null, null);
- verify(mView).setPadding(eq(DEFAULT), eq(0), eq(0), eq(0));
- mTunablePadding.destroy();
-
- mTunablePadding = TunablePadding.addTunablePadding(mView, KEY, DEFAULT,
- TunablePadding.FLAG_TOP);
- mTunablePadding.onTuningChanged(null, null);
- verify(mView).setPadding(eq(0), eq(DEFAULT), eq(0), eq(0));
- mTunablePadding.destroy();
-
- mTunablePadding = TunablePadding.addTunablePadding(mView, KEY, DEFAULT,
- TunablePadding.FLAG_END);
- mTunablePadding.onTuningChanged(null, null);
- verify(mView).setPadding(eq(0), eq(0), eq(DEFAULT), eq(0));
- mTunablePadding.destroy();
-
- mTunablePadding = TunablePadding.addTunablePadding(mView, KEY, DEFAULT,
- TunablePadding.FLAG_BOTTOM);
- mTunablePadding.onTuningChanged(null, null);
- verify(mView).setPadding(eq(0), eq(0), eq(0), eq(DEFAULT));
- mTunablePadding.destroy();
- }
-
- @Test
- public void testRtl() {
- when(mView.isLayoutRtl()).thenReturn(true);
-
- mTunablePadding = TunablePadding.addTunablePadding(mView, KEY, DEFAULT,
- TunablePadding.FLAG_END);
- mTunablePadding.onTuningChanged(null, null);
- verify(mView).setPadding(eq(DEFAULT), eq(0), eq(0), eq(0));
- mTunablePadding.destroy();
-
- mTunablePadding = TunablePadding.addTunablePadding(mView, KEY, DEFAULT,
- TunablePadding.FLAG_START);
- mTunablePadding.onTuningChanged(null, null);
- verify(mView).setPadding(eq(0), eq(0), eq(DEFAULT), eq(0));
- mTunablePadding.destroy();
- }
-
- @Test
- public void testTuning() {
- int value = 3;
- mTunablePadding = TunablePadding.addTunablePadding(mView, KEY, DEFAULT,
- TunablePadding.FLAG_START);
- mTunablePadding.onTuningChanged(KEY, String.valueOf(value));
-
- DisplayMetrics metrics = new DisplayMetrics();
- mContext.getSystemService(WindowManager.class).getDefaultDisplay().getMetrics(metrics);
- int output = (int) (metrics.density * value);
- verify(mView).setPadding(eq(output), eq(0), eq(0), eq(0));
-
- mTunablePadding.destroy();
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/settings/SettingsProxyTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/settings/SettingsProxyTest.kt
index dd791e764e01..5ac61102fa99 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/settings/SettingsProxyTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/settings/SettingsProxyTest.kt
@@ -28,9 +28,10 @@ import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.CoroutineDispatcher
-import kotlinx.coroutines.launch
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.advanceUntilIdle
import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertThrows
import org.junit.Before
@@ -44,6 +45,7 @@ import org.mockito.kotlin.eq
@RunWith(AndroidJUnit4::class)
@SmallTest
@TestableLooper.RunWithLooper
+@OptIn(ExperimentalCoroutinesApi::class)
class SettingsProxyTest : SysuiTestCase() {
private val testDispatcher = StandardTestDispatcher()
@@ -60,11 +62,12 @@ class SettingsProxyTest : SysuiTestCase() {
}
@Test
- fun registerContentObserver_inputString_success() {
- mSettings.registerContentObserverSync(TEST_SETTING, mContentObserver)
- verify(mSettings.getContentResolver())
- .registerContentObserver(eq(TEST_SETTING_URI), eq(false), eq(mContentObserver))
- }
+ fun registerContentObserver_inputString_success() =
+ testScope.runTest {
+ mSettings.registerContentObserverSync(TEST_SETTING, mContentObserver)
+ verify(mSettings.getContentResolver())
+ .registerContentObserver(eq(TEST_SETTING_URI), eq(false), eq(mContentObserver))
+ }
@Test
fun registerContentObserverSuspend_inputString_success() =
@@ -75,24 +78,25 @@ class SettingsProxyTest : SysuiTestCase() {
}
@Test
- fun registerContentObserverAsync_inputString_success() {
- mSettings.registerContentObserverAsync(TEST_SETTING, mContentObserver)
- testScope.launch {
+ fun registerContentObserverAsync_inputString_success() =
+ testScope.runTest {
+ mSettings.registerContentObserverAsync(TEST_SETTING, mContentObserver)
+ testScope.advanceUntilIdle()
verify(mSettings.getContentResolver())
.registerContentObserver(eq(TEST_SETTING_URI), eq(false), eq(mContentObserver))
}
- }
@Test
- fun registerContentObserver_inputString_notifyForDescendants_true() {
- mSettings.registerContentObserverSync(
- TEST_SETTING,
- notifyForDescendants = true,
- mContentObserver
- )
- verify(mSettings.getContentResolver())
- .registerContentObserver(eq(TEST_SETTING_URI), eq(true), eq(mContentObserver))
- }
+ fun registerContentObserver_inputString_notifyForDescendants_true() =
+ testScope.runTest {
+ mSettings.registerContentObserverSync(
+ TEST_SETTING,
+ notifyForDescendants = true,
+ mContentObserver
+ )
+ verify(mSettings.getContentResolver())
+ .registerContentObserver(eq(TEST_SETTING_URI), eq(true), eq(mContentObserver))
+ }
@Test
fun registerContentObserverSuspend_inputString_notifyForDescendants_true() =
@@ -107,24 +111,25 @@ class SettingsProxyTest : SysuiTestCase() {
}
@Test
- fun registerContentObserverAsync_inputString_notifyForDescendants_true() {
- mSettings.registerContentObserverAsync(
- TEST_SETTING,
- notifyForDescendants = true,
- mContentObserver
- )
- testScope.launch {
+ fun registerContentObserverAsync_inputString_notifyForDescendants_true() =
+ testScope.runTest {
+ mSettings.registerContentObserverAsync(
+ TEST_SETTING,
+ notifyForDescendants = true,
+ mContentObserver
+ )
+ testScope.advanceUntilIdle()
verify(mSettings.getContentResolver())
.registerContentObserver(eq(TEST_SETTING_URI), eq(true), eq(mContentObserver))
}
- }
@Test
- fun registerContentObserver_inputUri_success() {
- mSettings.registerContentObserverSync(TEST_SETTING_URI, mContentObserver)
- verify(mSettings.getContentResolver())
- .registerContentObserver(eq(TEST_SETTING_URI), eq(false), eq(mContentObserver))
- }
+ fun registerContentObserver_inputUri_success() =
+ testScope.runTest {
+ mSettings.registerContentObserverSync(TEST_SETTING_URI, mContentObserver)
+ verify(mSettings.getContentResolver())
+ .registerContentObserver(eq(TEST_SETTING_URI), eq(false), eq(mContentObserver))
+ }
@Test
fun registerContentObserverSuspend_inputUri_success() =
@@ -135,24 +140,25 @@ class SettingsProxyTest : SysuiTestCase() {
}
@Test
- fun registerContentObserverAsync_inputUri_success() {
- mSettings.registerContentObserverAsync(TEST_SETTING_URI, mContentObserver)
- testScope.launch {
+ fun registerContentObserverAsync_inputUri_success() =
+ testScope.runTest {
+ mSettings.registerContentObserverAsync(TEST_SETTING_URI, mContentObserver)
+ testScope.advanceUntilIdle()
verify(mSettings.getContentResolver())
.registerContentObserver(eq(TEST_SETTING_URI), eq(false), eq(mContentObserver))
}
- }
@Test
- fun registerContentObserver_inputUri_notifyForDescendants_true() {
- mSettings.registerContentObserverSync(
- TEST_SETTING_URI,
- notifyForDescendants = true,
- mContentObserver
- )
- verify(mSettings.getContentResolver())
- .registerContentObserver(eq(TEST_SETTING_URI), eq(true), eq(mContentObserver))
- }
+ fun registerContentObserver_inputUri_notifyForDescendants_true() =
+ testScope.runTest {
+ mSettings.registerContentObserverSync(
+ TEST_SETTING_URI,
+ notifyForDescendants = true,
+ mContentObserver
+ )
+ verify(mSettings.getContentResolver())
+ .registerContentObserver(eq(TEST_SETTING_URI), eq(true), eq(mContentObserver))
+ }
@Test
fun registerContentObserverSuspend_inputUri_notifyForDescendants_true() =
@@ -167,25 +173,58 @@ class SettingsProxyTest : SysuiTestCase() {
}
@Test
- fun registerContentObserverAsync_inputUri_notifyForDescendants_true() {
- mSettings.registerContentObserverAsync(
- TEST_SETTING_URI,
- notifyForDescendants = true,
- mContentObserver
- )
- testScope.launch {
+ fun registerContentObserverAsync_inputUri_notifyForDescendants_true() =
+ testScope.runTest {
+ mSettings.registerContentObserverAsync(
+ TEST_SETTING_URI,
+ notifyForDescendants = true,
+ mContentObserver
+ )
+ testScope.advanceUntilIdle()
verify(mSettings.getContentResolver())
.registerContentObserver(eq(TEST_SETTING_URI), eq(true), eq(mContentObserver))
}
- }
@Test
- fun unregisterContentObserverSync() {
- mSettings.unregisterContentObserverSync(mContentObserver)
- verify(mSettings.getContentResolver()).unregisterContentObserver(eq(mContentObserver))
+ fun registerContentObserverAsync_registeredLambdaPassed_callsCallback() =
+ testScope.runTest {
+ verifyRegisteredCallbackForRegistration {
+ mSettings.registerContentObserverAsync(TEST_SETTING, mContentObserver, it)
+ }
+ verifyRegisteredCallbackForRegistration {
+ mSettings.registerContentObserverAsync(TEST_SETTING_URI, mContentObserver, it)
+ }
+ verifyRegisteredCallbackForRegistration {
+ mSettings.registerContentObserverAsync(TEST_SETTING, false, mContentObserver, it)
+ }
+ verifyRegisteredCallbackForRegistration {
+ mSettings.registerContentObserverAsync(
+ TEST_SETTING_URI,
+ false,
+ mContentObserver,
+ it
+ )
+ }
+ }
+
+ private fun verifyRegisteredCallbackForRegistration(
+ call: (registeredRunnable: Runnable) -> Unit
+ ) {
+ var callbackCalled = false
+ val runnable = { callbackCalled = true }
+ call(runnable)
+ testScope.advanceUntilIdle()
+ assertThat(callbackCalled).isTrue()
}
@Test
+ fun unregisterContentObserverSync() =
+ testScope.runTest {
+ mSettings.unregisterContentObserverSync(mContentObserver)
+ verify(mSettings.getContentResolver()).unregisterContentObserver(eq(mContentObserver))
+ }
+
+ @Test
fun unregisterContentObserverSuspend_inputString_success() =
testScope.runTest {
mSettings.unregisterContentObserver(mContentObserver)
@@ -193,12 +232,12 @@ class SettingsProxyTest : SysuiTestCase() {
}
@Test
- fun unregisterContentObserverAsync_inputString_success() {
- mSettings.unregisterContentObserverAsync(mContentObserver)
- testScope.launch {
+ fun unregisterContentObserverAsync_inputString_success() =
+ testScope.runTest {
+ mSettings.unregisterContentObserverAsync(mContentObserver)
+ testScope.advanceUntilIdle()
verify(mSettings.getContentResolver()).unregisterContentObserver(eq(mContentObserver))
}
- }
@Test
fun getString_keyPresent_returnValidValue() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/settings/UserSettingsProxyTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/settings/UserSettingsProxyTest.kt
index e3e20c8ed501..5f7420d5a16b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/settings/UserSettingsProxyTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/settings/UserSettingsProxyTest.kt
@@ -31,9 +31,11 @@ import com.android.systemui.settings.FakeUserTracker
import com.android.systemui.settings.UserTracker
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.advanceUntilIdle
import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertThrows
import org.junit.Before
@@ -65,20 +67,21 @@ class UserSettingsProxyTest : SysuiTestCase() {
}
@Test
- fun registerContentObserverForUser_inputString_success() {
- mSettings.registerContentObserverForUserSync(
- TEST_SETTING,
- mContentObserver,
- mUserTracker.userId
- )
- verify(mSettings.getContentResolver())
- .registerContentObserver(
- eq(TEST_SETTING_URI),
- eq(false),
- eq(mContentObserver),
- eq(MAIN_USER_ID)
+ fun registerContentObserverForUser_inputString_success() =
+ testScope.runTest {
+ mSettings.registerContentObserverForUserSync(
+ TEST_SETTING,
+ mContentObserver,
+ mUserTracker.userId
)
- }
+ verify(mSettings.getContentResolver())
+ .registerContentObserver(
+ eq(TEST_SETTING_URI),
+ eq(false),
+ eq(mContentObserver),
+ eq(MAIN_USER_ID)
+ )
+ }
@Test
fun registerContentObserverForUserSuspend_inputString_success() =
@@ -98,13 +101,14 @@ class UserSettingsProxyTest : SysuiTestCase() {
}
@Test
- fun registerContentObserverForUserAsync_inputString_success() {
- mSettings.registerContentObserverForUserAsync(
- TEST_SETTING,
- mContentObserver,
- mUserTracker.userId
- )
- testScope.launch {
+ fun registerContentObserverForUserAsync_inputString_success() =
+ testScope.runTest {
+ mSettings.registerContentObserverForUserAsync(
+ TEST_SETTING,
+ mContentObserver,
+ mUserTracker.userId
+ )
+ testScope.advanceUntilIdle()
verify(mSettings.getContentResolver())
.registerContentObserver(
eq(TEST_SETTING_URI),
@@ -113,24 +117,24 @@ class UserSettingsProxyTest : SysuiTestCase() {
eq(MAIN_USER_ID)
)
}
- }
@Test
- fun registerContentObserverForUser_inputString_notifyForDescendants_true() {
- mSettings.registerContentObserverForUserSync(
- TEST_SETTING,
- notifyForDescendants = true,
- mContentObserver,
- mUserTracker.userId
- )
- verify(mSettings.getContentResolver())
- .registerContentObserver(
- eq(TEST_SETTING_URI),
- eq(true),
- eq(mContentObserver),
- eq(MAIN_USER_ID)
+ fun registerContentObserverForUser_inputString_notifyForDescendants_true() =
+ testScope.runTest {
+ mSettings.registerContentObserverForUserSync(
+ TEST_SETTING,
+ notifyForDescendants = true,
+ mContentObserver,
+ mUserTracker.userId
)
- }
+ verify(mSettings.getContentResolver())
+ .registerContentObserver(
+ eq(TEST_SETTING_URI),
+ eq(true),
+ eq(mContentObserver),
+ eq(MAIN_USER_ID)
+ )
+ }
@Test
fun registerContentObserverForUserSuspend_inputString_notifyForDescendants_true() =
@@ -153,14 +157,15 @@ class UserSettingsProxyTest : SysuiTestCase() {
}
@Test
- fun registerContentObserverForUserAsync_inputString_notifyForDescendants_true() {
- mSettings.registerContentObserverForUserAsync(
- TEST_SETTING,
- notifyForDescendants = true,
- mContentObserver,
- mUserTracker.userId
- )
- testScope.launch {
+ fun registerContentObserverForUserAsync_inputString_notifyForDescendants_true() =
+ testScope.runTest {
+ mSettings.registerContentObserverForUserAsync(
+ TEST_SETTING,
+ notifyForDescendants = true,
+ mContentObserver,
+ mUserTracker.userId
+ )
+ testScope.advanceUntilIdle()
verify(mSettings.getContentResolver())
.registerContentObserver(
eq(TEST_SETTING_URI),
@@ -169,23 +174,23 @@ class UserSettingsProxyTest : SysuiTestCase() {
eq(MAIN_USER_ID)
)
}
- }
@Test
- fun registerContentObserverForUser_inputUri_success() {
- mSettings.registerContentObserverForUserSync(
- TEST_SETTING_URI,
- mContentObserver,
- mUserTracker.userId
- )
- verify(mSettings.getContentResolver())
- .registerContentObserver(
- eq(TEST_SETTING_URI),
- eq(false),
- eq(mContentObserver),
- eq(MAIN_USER_ID)
+ fun registerContentObserverForUser_inputUri_success() =
+ testScope.runTest {
+ mSettings.registerContentObserverForUserSync(
+ TEST_SETTING_URI,
+ mContentObserver,
+ mUserTracker.userId
)
- }
+ verify(mSettings.getContentResolver())
+ .registerContentObserver(
+ eq(TEST_SETTING_URI),
+ eq(false),
+ eq(mContentObserver),
+ eq(MAIN_USER_ID)
+ )
+ }
@Test
fun registerContentObserverForUserSuspend_inputUri_success() =
@@ -205,13 +210,15 @@ class UserSettingsProxyTest : SysuiTestCase() {
}
@Test
- fun registerContentObserverForUserAsync_inputUri_success() {
- mSettings.registerContentObserverForUserAsync(
- TEST_SETTING_URI,
- mContentObserver,
- mUserTracker.userId
- )
- testScope.launch {
+ fun registerContentObserverForUserAsync_inputUri_success() =
+ testScope.runTest {
+ mSettings.registerContentObserverForUserAsync(
+ TEST_SETTING_URI,
+ mContentObserver,
+ mUserTracker.userId
+ )
+ testScope.advanceUntilIdle()
+
verify(mSettings.getContentResolver())
.registerContentObserver(
eq(TEST_SETTING_URI),
@@ -220,24 +227,41 @@ class UserSettingsProxyTest : SysuiTestCase() {
eq(MAIN_USER_ID)
)
}
- }
+ @OptIn(ExperimentalCoroutinesApi::class)
@Test
- fun registerContentObserverForUser_inputUri_notifyForDescendants_true() {
- mSettings.registerContentObserverForUserSync(
- TEST_SETTING_URI,
- notifyForDescendants = true,
- mContentObserver,
- mUserTracker.userId
- )
- verify(mSettings.getContentResolver())
- .registerContentObserver(
- eq(TEST_SETTING_URI),
- eq(true),
- eq(mContentObserver),
- eq(MAIN_USER_ID)
+ fun registerContentObserverForUserAsync_callbackAfterRegister() =
+ testScope.runTest {
+ var callbackCalled = false
+ val runnable = { callbackCalled = true }
+
+ mSettings.registerContentObserverForUserAsync(
+ TEST_SETTING_URI,
+ mContentObserver,
+ mUserTracker.userId,
+ runnable
)
- }
+ testScope.advanceUntilIdle()
+ assertThat(callbackCalled).isTrue()
+ }
+
+ @Test
+ fun registerContentObserverForUser_inputUri_notifyForDescendants_true() =
+ testScope.runTest {
+ mSettings.registerContentObserverForUserSync(
+ TEST_SETTING_URI,
+ notifyForDescendants = true,
+ mContentObserver,
+ mUserTracker.userId
+ )
+ verify(mSettings.getContentResolver())
+ .registerContentObserver(
+ eq(TEST_SETTING_URI),
+ eq(true),
+ eq(mContentObserver),
+ eq(MAIN_USER_ID)
+ )
+ }
@Test
fun registerContentObserverForUserSuspend_inputUri_notifyForDescendants_true() =
@@ -260,14 +284,15 @@ class UserSettingsProxyTest : SysuiTestCase() {
}
@Test
- fun registerContentObserverForUserAsync_inputUri_notifyForDescendants_true() {
- mSettings.registerContentObserverForUserAsync(
- TEST_SETTING_URI,
- notifyForDescendants = true,
- mContentObserver,
- mUserTracker.userId
- )
- testScope.launch {
+ fun registerContentObserverForUserAsync_inputUri_notifyForDescendants_true() =
+ testScope.runTest {
+ mSettings.registerContentObserverForUserAsync(
+ TEST_SETTING_URI,
+ notifyForDescendants = true,
+ mContentObserver,
+ mUserTracker.userId
+ )
+ testScope.advanceUntilIdle()
verify(mSettings.getContentResolver())
.registerContentObserver(
eq(TEST_SETTING_URI),
@@ -276,14 +301,19 @@ class UserSettingsProxyTest : SysuiTestCase() {
eq(MAIN_USER_ID)
)
}
- }
@Test
- fun registerContentObserver_inputUri_success() {
- mSettings.registerContentObserverSync(TEST_SETTING_URI, mContentObserver)
- verify(mSettings.getContentResolver())
- .registerContentObserver(eq(TEST_SETTING_URI), eq(false), eq(mContentObserver), eq(0))
- }
+ fun registerContentObserver_inputUri_success() =
+ testScope.runTest {
+ mSettings.registerContentObserverSync(TEST_SETTING_URI, mContentObserver)
+ verify(mSettings.getContentResolver())
+ .registerContentObserver(
+ eq(TEST_SETTING_URI),
+ eq(false),
+ eq(mContentObserver),
+ eq(0)
+ )
+ }
@Test
fun registerContentObserverSuspend_inputUri_success() =
@@ -313,33 +343,26 @@ class UserSettingsProxyTest : SysuiTestCase() {
}
@Test
- fun registerContentObserver_inputUri_notifyForDescendants_true() {
- mSettings.registerContentObserverSync(
- TEST_SETTING_URI,
- notifyForDescendants = true,
- mContentObserver
- )
- verify(mSettings.getContentResolver())
- .registerContentObserver(eq(TEST_SETTING_URI), eq(true), eq(mContentObserver), eq(0))
- }
-
- @Test
- fun registerContentObserverSuspend_inputUri_notifyForDescendants_true() =
+ fun registerContentObserver_inputUri_notifyForDescendants_true() =
testScope.runTest {
- mSettings.registerContentObserver(TEST_SETTING_URI, mContentObserver)
+ mSettings.registerContentObserverSync(
+ TEST_SETTING_URI,
+ notifyForDescendants = true,
+ mContentObserver
+ )
verify(mSettings.getContentResolver())
.registerContentObserver(
eq(TEST_SETTING_URI),
- eq(false),
+ eq(true),
eq(mContentObserver),
eq(0)
)
}
@Test
- fun registerContentObserverAsync_inputUri_notifyForDescendants_true() {
- mSettings.registerContentObserverAsync(TEST_SETTING_URI, mContentObserver)
- testScope.launch {
+ fun registerContentObserverSuspend_inputUri_notifyForDescendants_true() =
+ testScope.runTest {
+ mSettings.registerContentObserver(TEST_SETTING_URI, mContentObserver)
verify(mSettings.getContentResolver())
.registerContentObserver(
eq(TEST_SETTING_URI),
@@ -348,7 +371,21 @@ class UserSettingsProxyTest : SysuiTestCase() {
eq(0)
)
}
- }
+
+ @Test
+ fun registerContentObserverAsync_inputUri_notifyForDescendants_true() =
+ testScope.runTest {
+ mSettings.registerContentObserverAsync(TEST_SETTING_URI, mContentObserver)
+ testScope.launch {
+ verify(mSettings.getContentResolver())
+ .registerContentObserver(
+ eq(TEST_SETTING_URI),
+ eq(false),
+ eq(mContentObserver),
+ eq(0)
+ )
+ }
+ }
@Test
fun getString_keyPresent_returnValidValue() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/CsdWarningDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/CsdWarningDialogTest.java
index c81623e627ae..49aedccde258 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/volume/CsdWarningDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/CsdWarningDialogTest.java
@@ -19,28 +19,46 @@ package com.android.systemui.volume;
import static android.media.AudioManager.CSD_WARNING_DOSE_REACHED_1X;
import static android.media.AudioManager.CSD_WARNING_DOSE_REPEATED_5X;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
import android.app.Notification;
import android.app.NotificationManager;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.media.AudioManager;
+import android.platform.test.annotations.EnableFlags;
import android.testing.TestableLooper;
+import android.util.Pair;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.internal.messages.nano.SystemMessageProto;
+import com.android.systemui.Flags;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.plugins.VolumeDialog;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
+import com.google.common.collect.ImmutableList;
+
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.List;
+import java.util.Optional;
+
@SmallTest
@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
@@ -48,41 +66,109 @@ public class CsdWarningDialogTest extends SysuiTestCase {
private NotificationManager mNotificationManager;
private AudioManager mAudioManager;
+ private BroadcastDispatcher mFakeBroadcastDispatcher;
+ private CsdWarningDialog mDialog;
+ private static final String DISMISS_CSD_NOTIFICATION =
+ "com.android.systemui.volume.DISMISS_CSD_NOTIFICATION";
@Before
public void setup() {
mNotificationManager = mock(NotificationManager.class);
- getContext().addMockSystemService(NotificationManager.class, mNotificationManager);
+ mContext.addMockSystemService(NotificationManager.class, mNotificationManager);
mAudioManager = mock(AudioManager.class);
- getContext().addMockSystemService(AudioManager.class, mAudioManager);
+ mContext.addMockSystemService(AudioManager.class, mAudioManager);
+ mFakeBroadcastDispatcher = getFakeBroadcastDispatcher();
}
@Test
public void create1XCsdDialogAndWait_sendsNotification() {
FakeExecutor executor = new FakeExecutor(new FakeSystemClock());
// instantiate directly instead of via factory; we don't want executor to be @Background
- CsdWarningDialog dialog = new CsdWarningDialog(CSD_WARNING_DOSE_REACHED_1X, mContext,
- mAudioManager, mNotificationManager, executor, null);
+ mDialog = new CsdWarningDialog(CSD_WARNING_DOSE_REACHED_1X, mContext,
+ mAudioManager, mNotificationManager, executor, null,
+ Optional.of(ImmutableList.of(new Pair("", new Intent()))),
+ mFakeBroadcastDispatcher);
- dialog.show();
+ mDialog.show();
executor.advanceClockToLast();
executor.runAllReady();
- dialog.dismiss();
+ mDialog.dismiss();
verify(mNotificationManager).notify(
eq(SystemMessageProto.SystemMessage.NOTE_CSD_LOWER_AUDIO), any(Notification.class));
}
@Test
- public void create5XCsdDiSalogAndWait_willSendNotification() {
+ public void create5XCsdDialogAndWait_willSendNotification() {
FakeExecutor executor = new FakeExecutor(new FakeSystemClock());
- CsdWarningDialog dialog = new CsdWarningDialog(CSD_WARNING_DOSE_REPEATED_5X, mContext,
- mAudioManager, mNotificationManager, executor, null);
+ mDialog = new CsdWarningDialog(CSD_WARNING_DOSE_REPEATED_5X, mContext,
+ mAudioManager, mNotificationManager, executor, null,
+ Optional.of(ImmutableList.of(new Pair("", new Intent()))),
+ mFakeBroadcastDispatcher);
- dialog.show();
+ mDialog.show();
verify(mNotificationManager).notify(
eq(SystemMessageProto.SystemMessage.NOTE_CSD_LOWER_AUDIO), any(Notification.class));
}
+
+ @Test
+ @EnableFlags(Flags.FLAG_SOUNDDOSE_CUSTOMIZATION)
+ public void create1XCsdDialogWithActionsAndUndoIntent_willRegisterReceiverAndUndoVolume() {
+ FakeExecutor executor = new FakeExecutor(new FakeSystemClock());
+ Intent undoIntent = new Intent(VolumeDialog.ACTION_VOLUME_UNDO)
+ .setPackage(mContext.getPackageName());
+ mDialog = new CsdWarningDialog(CSD_WARNING_DOSE_REPEATED_5X, mContext,
+ mAudioManager, mNotificationManager, executor, null,
+ Optional.of(ImmutableList.of(new Pair("Undo", undoIntent))),
+ mFakeBroadcastDispatcher);
+
+ when(mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC)).thenReturn(25);
+ mDialog.show();
+ executor.advanceClockToLast();
+ executor.runAllReady();
+ mDialog.dismiss();
+ mDialog.mReceiverUndo.onReceive(mContext, undoIntent);
+
+ verify(mNotificationManager).notify(
+ eq(SystemMessageProto.SystemMessage.NOTE_CSD_LOWER_AUDIO),
+ any(Notification.class));
+ verify(mAudioManager).setStreamVolume(
+ eq(AudioManager.STREAM_MUSIC),
+ eq(25),
+ eq(AudioManager.FLAG_SHOW_UI));
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_SOUNDDOSE_CUSTOMIZATION)
+ public void deleteNotificationIntent_willUnregisterAllReceivers() {
+ FakeExecutor executor = new FakeExecutor(new FakeSystemClock());
+ Intent undoIntent = new Intent(VolumeDialog.ACTION_VOLUME_UNDO)
+ .setPackage(mContext.getPackageName());
+ mDialog = new CsdWarningDialog(CSD_WARNING_DOSE_REPEATED_5X, mContext,
+ mAudioManager, mNotificationManager, executor, null,
+ Optional.of(ImmutableList.of(new Pair("Undo", undoIntent))),
+ mFakeBroadcastDispatcher);
+ Intent dismissIntent = new Intent(DISMISS_CSD_NOTIFICATION)
+ .setPackage(mContext.getPackageName());
+
+ mDialog.mReceiverDismissNotification.onReceive(mContext, dismissIntent);
+ mDialog.show();
+ executor.advanceClockToLast();
+ executor.runAllReady();
+ mDialog.dismiss();
+
+ List<ResolveInfo> resolveInfoListDismiss = mContext.getPackageManager()
+ .queryBroadcastReceivers(dismissIntent, PackageManager.GET_RESOLVED_FILTER);
+ assertThat(resolveInfoListDismiss).hasSize(0);
+ List<ResolveInfo> resolveInfoListUndo = mContext.getPackageManager()
+ .queryBroadcastReceivers(undoIntent, PackageManager.GET_RESOLVED_FILTER);
+ assertThat(resolveInfoListUndo).hasSize(0);
+ }
+
+ @After
+ public void tearDown() {
+ mDialog.destroy();
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
index 6efb7d8fc3bb..cdfcca6c7065 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
@@ -43,6 +43,7 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.KeyguardManager;
+import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Canvas;
@@ -55,6 +56,7 @@ import android.platform.test.annotations.EnableFlags;
import android.provider.Settings;
import android.testing.TestableLooper;
import android.util.Log;
+import android.util.Pair;
import android.view.Gravity;
import android.view.InputDevice;
import android.view.MotionEvent;
@@ -92,6 +94,8 @@ import com.android.systemui.volume.domain.interactor.VolumePanelNavigationIntera
import com.android.systemui.volume.panel.shared.flag.VolumePanelFlag;
import com.android.systemui.volume.ui.navigation.VolumeNavigator;
+import com.google.common.collect.ImmutableList;
+
import dagger.Lazy;
import junit.framework.Assert;
@@ -107,6 +111,7 @@ import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import java.util.Arrays;
+import java.util.Optional;
import java.util.function.Predicate;
@SmallTest
@@ -157,11 +162,12 @@ public class VolumeDialogImplTest extends SysuiTestCase {
private final CsdWarningDialog.Factory mCsdWarningDialogFactory =
new CsdWarningDialog.Factory() {
- @Override
- public CsdWarningDialog create(int warningType, Runnable onCleanup) {
- return mCsdWarningDialog;
- }
- };
+ @Override
+ public CsdWarningDialog create(int warningType, Runnable onCleanup,
+ Optional<ImmutableList<Pair<String, Intent>>> actionIntents) {
+ return mCsdWarningDialog;
+ }
+ };
@Mock
private VibratorHelper mVibratorHelper;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index dc7a2c320855..6c4608d37c6e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -192,6 +192,7 @@ import com.android.wm.shell.transition.Transitions;
import org.junit.After;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -1852,6 +1853,7 @@ public class BubblesTest extends SysuiTestCase {
any(Bubble.class), anyBoolean(), anyBoolean());
}
+ @Ignore("reason = b/351977103")
@Test
public void testShowStackEdu_isNotConversationBubble() {
// Setup
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/TestMocksModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/TestMocksModule.kt
index 7c53639a85a6..0f8833cfe9f7 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/TestMocksModule.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/TestMocksModule.kt
@@ -16,6 +16,7 @@
package com.android.systemui
import android.app.ActivityManager
+import android.app.DreamManager
import android.app.admin.DevicePolicyManager
import android.app.trust.TrustManager
import android.hardware.fingerprint.FingerprintManager
@@ -33,6 +34,7 @@ import com.android.systemui.animation.DialogTransitionAnimator
import com.android.systemui.biometrics.AuthController
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
import com.android.systemui.communal.domain.interactor.CommunalInteractor
+import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor
import com.android.systemui.demomode.DemoModeController
import com.android.systemui.dump.DumpManager
import com.android.systemui.keyguard.ScreenLifecycle
@@ -94,6 +96,7 @@ data class TestMocksModule(
@get:Provides val demoModeController: DemoModeController = mock(),
@get:Provides val deviceProvisionedController: DeviceProvisionedController = mock(),
@get:Provides val dozeParameters: DozeParameters = mock(),
+ @get:Provides val dreamManager: DreamManager = mock(),
@get:Provides val dumpManager: DumpManager = mock(),
@get:Provides val fingerprintManager: FingerprintManager = mock(),
@get:Provides val headsUpManager: HeadsUpManager = mock(),
@@ -132,6 +135,7 @@ data class TestMocksModule(
@get:Provides val systemUIDialogManager: SystemUIDialogManager = mock(),
@get:Provides val deviceEntryIconTransitions: Set<DeviceEntryIconTransition> = emptySet(),
@get:Provides val communalInteractor: CommunalInteractor = mock(),
+ @get:Provides val communalSceneInteractor: CommunalSceneInteractor = mock(),
@get:Provides val sceneLogger: SceneLogger = mock(),
@get:Provides val trustManager: TrustManager = mock(),
@get:Provides val primaryBouncerInteractor: PrimaryBouncerInteractor = mock(),
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/accessibility/FakeReduceBrightColorsController.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/accessibility/FakeReduceBrightColorsController.kt
index 8b0affe2d99d..e02042d26d45 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/accessibility/FakeReduceBrightColorsController.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/accessibility/FakeReduceBrightColorsController.kt
@@ -16,6 +16,8 @@
package com.android.systemui.accessibility
+import android.content.res.Resources
+import com.android.server.display.feature.flags.Flags
import com.android.systemui.qs.ReduceBrightColorsController
class FakeReduceBrightColorsController : ReduceBrightColorsController {
@@ -44,4 +46,20 @@ class FakeReduceBrightColorsController : ReduceBrightColorsController {
}
}
}
+
+ override fun setReduceBrightColorsFeatureAvailable(enabled: Boolean) {
+ // do nothing
+ }
+
+ override fun isReduceBrightColorsFeatureAvailable(): Boolean {
+ return true
+ }
+
+ override fun isInUpgradeMode(resources: Resources?): Boolean {
+ if (resources != null) {
+ return Flags.evenDimmer() &&
+ resources.getBoolean(com.android.internal.R.bool.config_evenDimmerEnabled)
+ }
+ return false
+ }
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/smartspace/data/repository/SmartspaceRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/db/DefaultWidgetPopulationKosmos.kt
index 0e4c923a3078..8d01fcd9fea3 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/smartspace/data/repository/SmartspaceRepositoryKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/db/DefaultWidgetPopulationKosmos.kt
@@ -14,11 +14,10 @@
* limitations under the License.
*/
-package com.android.systemui.smartspace.data.repository
+package com.android.systemui.communal.data.db
import com.android.systemui.kosmos.Kosmos
-import com.android.systemui.kosmos.Kosmos.Fixture
+import org.mockito.Mockito.mock
-val Kosmos.fakeSmartspaceRepository by Fixture { FakeSmartspaceRepository() }
-
-val Kosmos.smartspaceRepository by Fixture<SmartspaceRepository> { fakeSmartspaceRepository }
+val Kosmos.defaultWidgetPopulation by
+ Kosmos.Fixture<DefaultWidgetPopulation> { mock(DefaultWidgetPopulation::class.java) }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/CommunalSmartspaceRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/CommunalSmartspaceRepositoryKosmos.kt
new file mode 100644
index 000000000000..559a6eeb814a
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/CommunalSmartspaceRepositoryKosmos.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.communal.data.repository
+
+import com.android.systemui.kosmos.Kosmos
+
+val Kosmos.fakeCommunalSmartspaceRepository by Kosmos.Fixture { FakeCommunalSmartspaceRepository() }
+
+val Kosmos.communalSmartspaceRepository by
+ Kosmos.Fixture<CommunalSmartspaceRepository> { fakeCommunalSmartspaceRepository }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalMediaRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalMediaRepository.kt
index 1884a3264ed6..14b1984f2374 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalMediaRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalMediaRepository.kt
@@ -36,4 +36,18 @@ class FakeCommunalMediaRepository : CommunalMediaRepository {
fun mediaInactive() {
_mediaModel.value = CommunalMediaModel.INACTIVE
}
+
+ private var isListening = false
+
+ override fun startListening() {
+ isListening = true
+ }
+
+ override fun stopListening() {
+ isListening = false
+ }
+
+ fun isListening(): Boolean {
+ return isListening
+ }
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalSmartspaceRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalSmartspaceRepository.kt
new file mode 100644
index 000000000000..904ab4bc3f85
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalSmartspaceRepository.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.communal.data.repository
+
+import com.android.systemui.communal.data.model.CommunalSmartspaceTimer
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+
+class FakeCommunalSmartspaceRepository : CommunalSmartspaceRepository {
+
+ private val _timers = MutableStateFlow<List<CommunalSmartspaceTimer>>(emptyList())
+ override val timers: Flow<List<CommunalSmartspaceTimer>> = _timers
+
+ fun setTimers(timers: List<CommunalSmartspaceTimer>) {
+ _timers.value = timers
+ }
+
+ private var isListening = false
+
+ override fun startListening() {
+ isListening = true
+ }
+
+ override fun stopListening() {
+ isListening = false
+ }
+
+ fun isListening(): Boolean {
+ return isListening
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt
index b58861b1104e..eb9278537db5 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt
@@ -19,6 +19,7 @@ package com.android.systemui.communal.domain.interactor
import android.os.userManager
import com.android.systemui.broadcast.broadcastDispatcher
import com.android.systemui.communal.data.repository.communalMediaRepository
+import com.android.systemui.communal.data.repository.communalSmartspaceRepository
import com.android.systemui.communal.data.repository.communalWidgetRepository
import com.android.systemui.communal.widgets.EditWidgetsActivityStarter
import com.android.systemui.flags.Flags
@@ -34,7 +35,6 @@ import com.android.systemui.log.logcatLogBuffer
import com.android.systemui.plugins.activityStarter
import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.settings.userTracker
-import com.android.systemui.smartspace.data.repository.smartspaceRepository
import com.android.systemui.user.data.repository.fakeUserRepository
import com.android.systemui.util.mockito.mock
@@ -47,7 +47,7 @@ val Kosmos.communalInteractor by Fixture {
widgetRepository = communalWidgetRepository,
communalPrefsInteractor = communalPrefsInteractor,
mediaRepository = communalMediaRepository,
- smartspaceRepository = smartspaceRepository,
+ smartspaceRepository = communalSmartspaceRepository,
keyguardInteractor = keyguardInteractor,
keyguardTransitionInteractor = keyguardTransitionInteractor,
communalSettingsInteractor = communalSettingsInteractor,
@@ -64,13 +64,17 @@ val Kosmos.communalInteractor by Fixture {
val Kosmos.editWidgetsActivityStarter by Fixture<EditWidgetsActivityStarter> { mock() }
-suspend fun Kosmos.setCommunalAvailable(available: Boolean) {
- fakeFeatureFlagsClassic.set(Flags.COMMUNAL_SERVICE_ENABLED, available)
- if (available) {
+suspend fun Kosmos.setCommunalEnabled(enabled: Boolean) {
+ fakeFeatureFlagsClassic.set(Flags.COMMUNAL_SERVICE_ENABLED, enabled)
+ if (enabled) {
fakeUserRepository.asMainUser()
} else {
fakeUserRepository.asDefaultUser()
}
+}
+
+suspend fun Kosmos.setCommunalAvailable(available: Boolean) {
+ setCommunalEnabled(available)
with(fakeKeyguardRepository) {
setIsEncryptedOrLockdown(!available)
setKeyguardShowing(available)
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/haptics/qs/QSLongPressEffectKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/haptics/qs/QSLongPressEffectKosmos.kt
index eff99e047f45..28355e1c3efa 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/haptics/qs/QSLongPressEffectKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/haptics/qs/QSLongPressEffectKosmos.kt
@@ -16,9 +16,10 @@
package com.android.systemui.haptics.qs
+import com.android.systemui.classifier.falsingManager
import com.android.systemui.haptics.vibratorHelper
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.statusbar.policy.keyguardStateController
val Kosmos.qsLongPressEffect by
- Kosmos.Fixture { QSLongPressEffect(vibratorHelper, keyguardStateController) }
+ Kosmos.Fixture { QSLongPressEffect(vibratorHelper, keyguardStateController, falsingManager) }
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
index f436a68aa5be..001b55b99919 100644
--- 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
@@ -25,6 +25,7 @@ import com.android.systemui.keyboard.shortcut.data.repository.ShortcutHelperCate
import com.android.systemui.keyboard.shortcut.data.repository.ShortcutHelperStateRepository
import com.android.systemui.keyboard.shortcut.data.repository.ShortcutHelperTestHelper
import com.android.systemui.keyboard.shortcut.data.source.AppCategoriesShortcutsSource
+import com.android.systemui.keyboard.shortcut.data.source.CurrentAppShortcutsSource
import com.android.systemui.keyboard.shortcut.data.source.InputShortcutsSource
import com.android.systemui.keyboard.shortcut.data.source.KeyboardShortcutGroupsSource
import com.android.systemui.keyboard.shortcut.data.source.MultitaskingShortcutsSource
@@ -67,18 +68,23 @@ val Kosmos.shortcutHelperStateRepository by
)
}
-val Kosmos.shortcutHelperInputShortcutsSource by
+var Kosmos.shortcutHelperInputShortcutsSource: KeyboardShortcutGroupsSource by
Kosmos.Fixture { InputShortcutsSource(mainResources, windowManager) }
+var Kosmos.shortcutHelperCurrentAppShortcutsSource: KeyboardShortcutGroupsSource by
+ Kosmos.Fixture { CurrentAppShortcutsSource(windowManager) }
+
val Kosmos.shortcutHelperCategoriesRepository by
Kosmos.Fixture {
ShortcutHelperCategoriesRepository(
applicationContext,
+ applicationCoroutineScope,
testDispatcher,
shortcutHelperSystemShortcutsSource,
shortcutHelperMultiTaskingShortcutsSource,
shortcutHelperAppCategoriesShortcutsSource,
shortcutHelperInputShortcutsSource,
+ shortcutHelperCurrentAppShortcutsSource,
fakeInputManager.inputManager,
shortcutHelperStateRepository,
)
@@ -91,7 +97,8 @@ val Kosmos.shortcutHelperTestHelper by
applicationContext,
broadcastDispatcher,
fakeCommandQueue,
- windowManager
+ fakeInputManager,
+ windowManager,
)
}
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
index 40510db24f47..3e09b2379ff1 100644
--- 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
@@ -18,6 +18,7 @@ package com.android.systemui.keyboard.shortcut.data.repository
import android.content.Context
import android.content.Intent
+import android.hardware.input.FakeInputManager
import android.view.KeyboardShortcutGroup
import android.view.WindowManager
import android.view.WindowManager.KeyboardShortcutsReceiver
@@ -31,6 +32,7 @@ class ShortcutHelperTestHelper(
private val context: Context,
private val fakeBroadcastDispatcher: FakeBroadcastDispatcher,
private val fakeCommandQueue: FakeCommandQueue,
+ private val fakeInputManager: FakeInputManager,
windowManager: WindowManager
) {
@@ -79,6 +81,7 @@ class ShortcutHelperTestHelper(
}
fun toggle(deviceId: Int) {
+ fakeInputManager.addPhysicalKeyboard(deviceId)
fakeCommandQueue.doForEachCallback { it.toggleKeyboardShortcutsMenu(deviceId) }
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractorKosmos.kt
index 446652c7c6d8..126d85890531 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractorKosmos.kt
@@ -16,7 +16,9 @@
package com.android.systemui.keyguard.domain.interactor
+import android.service.dream.dreamManager
import com.android.systemui.communal.domain.interactor.communalInteractor
+import com.android.systemui.communal.domain.interactor.communalSceneInteractor
import com.android.systemui.deviceentry.data.repository.deviceEntryRepository
import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository
import com.android.systemui.kosmos.Kosmos
@@ -36,9 +38,11 @@ var Kosmos.fromDozingTransitionInteractor by
mainDispatcher = testDispatcher,
keyguardInteractor = keyguardInteractor,
communalInteractor = communalInteractor,
+ communalSceneInteractor = communalSceneInteractor,
powerInteractor = powerInteractor,
keyguardOcclusionInteractor = keyguardOcclusionInteractor,
deviceEntryRepository = deviceEntryRepository,
wakeToGoneInteractor = keyguardWakeDirectlyToGoneInteractor,
+ dreamManager = dreamManager
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorKosmos.kt
index 4328ca153374..406b5cb11bb4 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorKosmos.kt
@@ -16,11 +16,9 @@
package com.android.systemui.keyguard.domain.interactor
-import android.content.applicationContext
import com.android.systemui.biometrics.domain.interactor.fingerprintPropertyInteractor
import com.android.systemui.common.ui.domain.interactor.configurationInteractor
import com.android.systemui.keyguard.data.repository.keyguardBlueprintRepository
-import com.android.systemui.keyguard.data.repository.keyguardClockSection
import com.android.systemui.keyguard.data.repository.keyguardSmartspaceSection
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
@@ -31,12 +29,9 @@ val Kosmos.keyguardBlueprintInteractor by
KeyguardBlueprintInteractor(
keyguardBlueprintRepository = keyguardBlueprintRepository,
applicationScope = applicationCoroutineScope,
- context = applicationContext,
shadeInteractor = shadeInteractor,
- clockInteractor = keyguardClockInteractor,
configurationInteractor = configurationInteractor,
fingerprintPropertyInteractor = fingerprintPropertyInteractor,
- clockSection = keyguardClockSection,
smartspaceSection = keyguardSmartspaceSection,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorKosmos.kt
index 03e5a90c9f7d..2c6d44f10152 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorKosmos.kt
@@ -19,7 +19,6 @@ package com.android.systemui.keyguard.domain.interactor
import com.android.systemui.keyguard.data.repository.keyguardRepository
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.testScope
-import com.android.systemui.scene.domain.interactor.sceneInteractor
import kotlinx.coroutines.ExperimentalCoroutinesApi
@ExperimentalCoroutinesApi
@@ -30,6 +29,5 @@ val Kosmos.keyguardDismissActionInteractor by
transitionInteractor = keyguardTransitionInteractor,
dismissInteractor = keyguardDismissInteractor,
applicationScope = testScope.backgroundScope,
- sceneInteractor = sceneInteractor,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilterKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilterKosmos.kt
index b8b006098c6f..147318473998 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilterKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilterKosmos.kt
@@ -21,6 +21,7 @@ import com.android.systemui.broadcast.BroadcastSender
import com.android.systemui.concurrency.fakeExecutor
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.media.controls.data.repository.mediaFilterRepository
+import com.android.systemui.media.controls.shared.mediaLogger
import com.android.systemui.media.controls.util.mediaFlags
import com.android.systemui.media.controls.util.mediaUiEventLogger
import com.android.systemui.settings.userTracker
@@ -45,6 +46,6 @@ val Kosmos.mediaDataFilter by
logger = mediaUiEventLogger,
mediaFlags = mediaFlags,
mediaFilterRepository = mediaFilterRepository,
- mediaLoadingLogger = mediaLoadingLogger,
+ mediaLogger = mediaLogger,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/MediaLoadingLoggerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/shared/MediaLoggerKosmos.kt
index 96886f738dbd..55c419e8ade1 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/MediaLoadingLoggerKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/shared/MediaLoggerKosmos.kt
@@ -14,12 +14,11 @@
* limitations under the License.
*/
-package com.android.systemui.media.controls.domain.pipeline
+package com.android.systemui.media.controls.shared
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.log.logcatLogBuffer
import org.mockito.Mockito.mock
-val Kosmos.mediaLoadingLogger by
- Kosmos.Fixture { MediaLoadingLogger(logcatLogBuffer("MediaLoadingLogBuffer")) }
-val Kosmos.mockMediaLoadingLogger by Kosmos.Fixture { mock(MediaLoadingLogger::class.java) }
+var Kosmos.mediaLogger by Kosmos.Fixture { MediaLogger(logcatLogBuffer("MediaLogBuffer")) }
+val Kosmos.mockMediaLogger by Kosmos.Fixture { mock(MediaLogger::class.java) }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModelKosmos.kt
index 069995aa3fec..054ac2e39993 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModelKosmos.kt
@@ -23,6 +23,7 @@ import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.media.controls.domain.pipeline.interactor.factory.mediaControlInteractorFactory
import com.android.systemui.media.controls.domain.pipeline.interactor.mediaCarouselInteractor
+import com.android.systemui.media.controls.shared.mediaLogger
import com.android.systemui.media.controls.util.mediaFlags
import com.android.systemui.media.controls.util.mediaUiEventLogger
import com.android.systemui.statusbar.notification.collection.provider.visualStabilityProvider
@@ -40,5 +41,6 @@ val Kosmos.mediaCarouselViewModel by
recommendationsViewModel = mediaRecommendationsViewModel,
logger = mediaUiEventLogger,
mediaFlags = mediaFlags,
+ mediaLogger = mediaLogger,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/IconTilesRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/DefaultLargeTilesRepositoryKosmos.kt
index e40152aa588f..92ac08949add 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/IconTilesRepositoryKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/DefaultLargeTilesRepositoryKosmos.kt
@@ -18,4 +18,5 @@ package com.android.systemui.qs.panels.data.repository
import com.android.systemui.kosmos.Kosmos
-var Kosmos.iconTilesRepository: IconTilesRepository by Kosmos.Fixture { IconTilesRepositoryImpl() }
+var Kosmos.defaultLargeTilesRepository: DefaultLargeTilesRepository by
+ Kosmos.Fixture { DefaultLargeTilesRepositoryImpl() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/QSPreferencesRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/QSPreferencesRepositoryKosmos.kt
index 39ae5eb44c65..513d4e418a41 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/QSPreferencesRepositoryKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/QSPreferencesRepositoryKosmos.kt
@@ -22,4 +22,11 @@ import com.android.systemui.settings.userFileManager
import com.android.systemui.user.data.repository.userRepository
val Kosmos.qsPreferencesRepository by
- Kosmos.Fixture { QSPreferencesRepository(userFileManager, userRepository, testDispatcher) }
+ Kosmos.Fixture {
+ QSPreferencesRepository(
+ userFileManager,
+ userRepository,
+ defaultLargeTilesRepository,
+ testDispatcher
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/IconTilesInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/IconTilesInteractorKosmos.kt
index eaa702f9f6da..76dccdb95637 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/IconTilesInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/IconTilesInteractorKosmos.kt
@@ -17,6 +17,16 @@
package com.android.systemui.qs.panels.domain.interactor
import com.android.systemui.kosmos.Kosmos
-import com.android.systemui.qs.panels.data.repository.iconTilesRepository
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.log.core.FakeLogBuffer
+import com.android.systemui.qs.panels.data.repository.defaultLargeTilesRepository
-val Kosmos.iconTilesInteractor by Kosmos.Fixture { IconTilesInteractor(iconTilesRepository) }
+val Kosmos.iconTilesInteractor by
+ Kosmos.Fixture {
+ IconTilesInteractor(
+ defaultLargeTilesRepository,
+ qsPreferencesInteractor,
+ FakeLogBuffer.Factory.create(),
+ applicationCoroutineScope
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/FakeShadeRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/FakeShadeRepository.kt
index b9918f1e46d8..4660337c0d4b 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/FakeShadeRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/FakeShadeRepository.kt
@@ -18,7 +18,6 @@
package com.android.systemui.shade.data.repository
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.shade.shared.model.ShadeMode
import dagger.Binds
import dagger.Module
import javax.inject.Inject
@@ -30,53 +29,65 @@ import kotlinx.coroutines.flow.asStateFlow
@SysUISingleton
class FakeShadeRepository @Inject constructor() : ShadeRepository {
private val _qsExpansion = MutableStateFlow(0f)
- @Deprecated("Use ShadeInteractor.qsExpansion instead") override val qsExpansion = _qsExpansion
+
+ @Deprecated("Use ShadeInteractor.qsExpansion instead")
+ override val qsExpansion = _qsExpansion.asStateFlow()
private val _udfpsTransitionToFullShadeProgress = MutableStateFlow(0f)
- override val udfpsTransitionToFullShadeProgress = _udfpsTransitionToFullShadeProgress
+ override val udfpsTransitionToFullShadeProgress =
+ _udfpsTransitionToFullShadeProgress.asStateFlow()
private val _currentFling: MutableStateFlow<FlingInfo?> = MutableStateFlow(null)
- override val currentFling: StateFlow<FlingInfo?> = _currentFling
+ override val currentFling: StateFlow<FlingInfo?> = _currentFling.asStateFlow()
private val _lockscreenShadeExpansion = MutableStateFlow(0f)
- override val lockscreenShadeExpansion = _lockscreenShadeExpansion
+ override val lockscreenShadeExpansion = _lockscreenShadeExpansion.asStateFlow()
private val _legacyShadeExpansion = MutableStateFlow(0f)
+
@Deprecated("Use ShadeInteractor instead")
- override val legacyShadeExpansion = _legacyShadeExpansion
+ override val legacyShadeExpansion = _legacyShadeExpansion.asStateFlow()
private val _legacyShadeTracking = MutableStateFlow(false)
+
@Deprecated("Use ShadeInteractor instead")
- override val legacyShadeTracking = _legacyShadeTracking
+ override val legacyShadeTracking = _legacyShadeTracking.asStateFlow()
private val _legacyQsTracking = MutableStateFlow(false)
- @Deprecated("Use ShadeInteractor instead") override val legacyQsTracking = _legacyQsTracking
+
+ @Deprecated("Use ShadeInteractor instead")
+ override val legacyQsTracking = _legacyQsTracking.asStateFlow()
private val _legacyExpandedOrAwaitingInputTransfer = MutableStateFlow(false)
+
@Deprecated("Use ShadeInteractor instead")
- override val legacyExpandedOrAwaitingInputTransfer = _legacyExpandedOrAwaitingInputTransfer
+ override val legacyExpandedOrAwaitingInputTransfer =
+ _legacyExpandedOrAwaitingInputTransfer.asStateFlow()
private val _legacyIsQsExpanded = MutableStateFlow(false)
- @Deprecated("Use ShadeInteractor instead") override val legacyIsQsExpanded = _legacyIsQsExpanded
+
+ @Deprecated("Use ShadeInteractor instead")
+ override val legacyIsQsExpanded = _legacyIsQsExpanded.asStateFlow()
@Deprecated("Use ShadeInteractor.isUserInteractingWithShade instead")
override val legacyLockscreenShadeTracking = MutableStateFlow(false)
- private val _shadeMode = MutableStateFlow<ShadeMode>(ShadeMode.Single)
- override val shadeMode: StateFlow<ShadeMode> = _shadeMode.asStateFlow()
-
private var _isDualShadeAlignedToBottom = false
override val isDualShadeAlignedToBottom
get() = _isDualShadeAlignedToBottom
+ private var _isShadeLayoutWide = MutableStateFlow(false)
+ override val isShadeLayoutWide: StateFlow<Boolean> = _isShadeLayoutWide.asStateFlow()
+
@Deprecated("Use ShadeInteractor instead")
override fun setLegacyIsQsExpanded(legacyIsQsExpanded: Boolean) {
_legacyIsQsExpanded.value = legacyIsQsExpanded
}
private val _legacyExpandImmediate = MutableStateFlow(false)
+
@Deprecated("Use ShadeInteractor instead")
- override val legacyExpandImmediate = _legacyExpandImmediate
+ override val legacyExpandImmediate = _legacyExpandImmediate.asStateFlow()
@Deprecated("Use ShadeInteractor instead")
override fun setLegacyExpandImmediate(legacyExpandImmediate: Boolean) {
@@ -106,6 +117,7 @@ class FakeShadeRepository @Inject constructor() : ShadeRepository {
}
private val _legacyQsFullscreen = MutableStateFlow(false)
+
@Deprecated("Use ShadeInteractor instead") override val legacyQsFullscreen = _legacyQsFullscreen
@Deprecated("Use ShadeInteractor instead")
@@ -114,6 +126,7 @@ class FakeShadeRepository @Inject constructor() : ShadeRepository {
}
private val _legacyIsClosing = MutableStateFlow(false)
+
@Deprecated("Use ShadeInteractor instead") override val legacyIsClosing = _legacyIsClosing
@Deprecated("Use ShadeInteractor instead")
@@ -142,13 +155,13 @@ class FakeShadeRepository @Inject constructor() : ShadeRepository {
_legacyShadeExpansion.value = expandedFraction
}
- override fun setShadeMode(mode: ShadeMode) {
- _shadeMode.value = mode
- }
-
fun setDualShadeAlignedToBottom(isAlignedToBottom: Boolean) {
_isDualShadeAlignedToBottom = isAlignedToBottom
}
+
+ override fun setShadeLayoutWide(isShadeLayoutWide: Boolean) {
+ _isShadeLayoutWide.value = isShadeLayoutWide
+ }
}
@Module
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeInteractorKosmos.kt
index a00d2f4fc517..bfd6614a2272 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeInteractorKosmos.kt
@@ -45,7 +45,6 @@ val Kosmos.shadeInteractorSceneContainerImpl by
scope = applicationCoroutineScope,
sceneInteractor = sceneInteractor,
sharedNotificationContainerInteractor = sharedNotificationContainerInteractor,
- shadeRepository = shadeRepository,
)
}
val Kosmos.shadeInteractorLegacyImpl by
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/smartspace/data/repository/FakeSmartspaceRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/smartspace/data/repository/FakeSmartspaceRepository.kt
deleted file mode 100644
index 862e52d7703f..000000000000
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/smartspace/data/repository/FakeSmartspaceRepository.kt
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.android.systemui.smartspace.data.repository
-
-import android.app.smartspace.SmartspaceTarget
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.MutableStateFlow
-
-class FakeSmartspaceRepository(
- smartspaceRemoteViewsEnabled: Boolean = true,
-) : SmartspaceRepository {
-
- override val isSmartspaceRemoteViewsEnabled = smartspaceRemoteViewsEnabled
-
- private val _communalSmartspaceTargets: MutableStateFlow<List<SmartspaceTarget>> =
- MutableStateFlow(emptyList())
- override val communalSmartspaceTargets: Flow<List<SmartspaceTarget>> =
- _communalSmartspaceTargets
-
- fun setCommunalSmartspaceTargets(targets: List<SmartspaceTarget>) {
- _communalSmartspaceTargets.value = targets
- }
-}
diff --git a/packages/VpnDialogs/res/values-fr-rCA/strings.xml b/packages/VpnDialogs/res/values-fr-rCA/strings.xml
index ad450b4c5f39..9ae0cb24246e 100644
--- a/packages/VpnDialogs/res/values-fr-rCA/strings.xml
+++ b/packages/VpnDialogs/res/values-fr-rCA/strings.xml
@@ -32,7 +32,7 @@
<string name="always_on_disconnected_message_settings_link" msgid="6172280302829992412">"Modifier les paramètres RPV"</string>
<string name="configure" msgid="4905518375574791375">"Configurer"</string>
<string name="disconnect" msgid="971412338304200056">"Déconnecter"</string>
- <string name="open_app" msgid="3717639178595958667">"Ouvrir l\'application"</string>
+ <string name="open_app" msgid="3717639178595958667">"Ouvrir l\'appli"</string>
<string name="dismiss" msgid="6192859333764711227">"Ignorer"</string>
<string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
<string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-fr-rCA/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-fr-rCA/strings.xml
index ea0a27b069da..4f922a57d4ad 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-fr-rCA/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-fr-rCA/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="display_cutout_emulation_overlay" msgid="3814493834951357513">"Rendre les applications sous la zone de découpe"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Rendre les applis sous la zone de découpe"</string>
</resources>
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
index 9fc64a965f4b..099cb2894515 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
@@ -26,7 +26,6 @@ import android.annotation.MainThread;
import android.annotation.NonNull;
import android.content.Context;
import android.graphics.Region;
-import android.hardware.input.InputManager;
import android.os.Looper;
import android.os.PowerManager;
import android.os.SystemClock;
@@ -56,7 +55,6 @@ import com.android.server.policy.WindowManagerPolicy;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.Objects;
import java.util.StringJoiner;
/**
@@ -748,8 +746,6 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
if ((mEnabledFeatures & FLAG_FEATURE_MOUSE_KEYS) != 0) {
mMouseKeysInterceptor = new MouseKeysInterceptor(mAms,
- Objects.requireNonNull(mContext.getSystemService(
- InputManager.class)),
Looper.myLooper(),
Display.DEFAULT_DISPLAY);
addFirstEventHandler(Display.DEFAULT_DISPLAY, mMouseKeysInterceptor);
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
index b061065d44a5..3706dccbb717 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
@@ -234,6 +234,8 @@ class AccessibilityUserState {
mAccessibilityShortcutKeyTargets.clear();
mAccessibilityButtonTargets.clear();
mAccessibilityGestureTargets.clear();
+ mAccessibilityQsTargets.clear();
+ mA11yTilesInQsPanel.clear();
mTargetAssignedToAccessibilityButton = null;
mIsTouchExplorationEnabled = false;
mServiceHandlesDoubleTap = false;
diff --git a/services/accessibility/java/com/android/server/accessibility/MouseKeysInterceptor.java b/services/accessibility/java/com/android/server/accessibility/MouseKeysInterceptor.java
index 3f0f23f4a2f9..56da231ad31a 100644
--- a/services/accessibility/java/com/android/server/accessibility/MouseKeysInterceptor.java
+++ b/services/accessibility/java/com/android/server/accessibility/MouseKeysInterceptor.java
@@ -23,7 +23,6 @@ import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.companion.virtual.VirtualDeviceManager;
import android.companion.virtual.VirtualDeviceParams;
-import android.hardware.input.InputManager;
import android.hardware.input.VirtualMouse;
import android.hardware.input.VirtualMouseButtonEvent;
import android.hardware.input.VirtualMouseConfig;
@@ -60,8 +59,8 @@ import com.android.server.companion.virtual.VirtualDeviceManagerInternal;
* In case multiple physical keyboard are connected to a device,
* mouse keys of each physical keyboard will control a single (global) mouse pointer.
*/
-public class MouseKeysInterceptor extends BaseEventStreamTransformation implements Handler.Callback,
- InputManager.InputDeviceListener {
+public class MouseKeysInterceptor extends BaseEventStreamTransformation
+ implements Handler.Callback {
private static final String LOG_TAG = "MouseKeysInterceptor";
// To enable these logs, run: 'adb shell setprop log.tag.MouseKeysInterceptor DEBUG'
@@ -77,11 +76,8 @@ public class MouseKeysInterceptor extends BaseEventStreamTransformation implemen
private static final int INTERVAL_MILLIS = 10;
private final AccessibilityManagerService mAms;
- private final InputManager mInputManager;
private final Handler mHandler;
- private final int mDisplayId;
-
VirtualDeviceManager.VirtualDevice mVirtualDevice = null;
private VirtualMouse mVirtualMouse = null;
@@ -100,23 +96,23 @@ public class MouseKeysInterceptor extends BaseEventStreamTransformation implemen
/** Last time the key action was performed */
private long mLastTimeKeyActionPerformed = 0;
- // TODO (b/346706749): This is currently using the numpad key bindings for mouse keys.
- // Decide the final mouse key bindings with UX input.
+ /** Whether scroll toggle is on */
+ private boolean mScrollToggleOn = false;
+
public enum MouseKeyEvent {
- DIAGONAL_DOWN_LEFT_MOVE(KeyEvent.KEYCODE_NUMPAD_1),
- DOWN_MOVE(KeyEvent.KEYCODE_NUMPAD_2),
- DIAGONAL_DOWN_RIGHT_MOVE(KeyEvent.KEYCODE_NUMPAD_3),
- LEFT_MOVE(KeyEvent.KEYCODE_NUMPAD_4),
- RIGHT_MOVE(KeyEvent.KEYCODE_NUMPAD_6),
- DIAGONAL_UP_LEFT_MOVE(KeyEvent.KEYCODE_NUMPAD_7),
- UP_MOVE(KeyEvent.KEYCODE_NUMPAD_8),
- DIAGONAL_UP_RIGHT_MOVE(KeyEvent.KEYCODE_NUMPAD_9),
- LEFT_CLICK(KeyEvent.KEYCODE_NUMPAD_5),
- RIGHT_CLICK(KeyEvent.KEYCODE_NUMPAD_DOT),
- HOLD(KeyEvent.KEYCODE_NUMPAD_MULTIPLY),
- RELEASE(KeyEvent.KEYCODE_NUMPAD_SUBTRACT),
- SCROLL_UP(KeyEvent.KEYCODE_A),
- SCROLL_DOWN(KeyEvent.KEYCODE_S);
+ DIAGONAL_UP_LEFT_MOVE(KeyEvent.KEYCODE_7),
+ UP_MOVE_OR_SCROLL(KeyEvent.KEYCODE_8),
+ DIAGONAL_UP_RIGHT_MOVE(KeyEvent.KEYCODE_9),
+ LEFT_MOVE(KeyEvent.KEYCODE_U),
+ RIGHT_MOVE(KeyEvent.KEYCODE_O),
+ DIAGONAL_DOWN_LEFT_MOVE(KeyEvent.KEYCODE_J),
+ DOWN_MOVE_OR_SCROLL(KeyEvent.KEYCODE_K),
+ DIAGONAL_DOWN_RIGHT_MOVE(KeyEvent.KEYCODE_L),
+ LEFT_CLICK(KeyEvent.KEYCODE_I),
+ RIGHT_CLICK(KeyEvent.KEYCODE_SLASH),
+ HOLD(KeyEvent.KEYCODE_M),
+ RELEASE(KeyEvent.KEYCODE_COMMA),
+ SCROLL_TOGGLE(KeyEvent.KEYCODE_PERIOD);
private final int mKeyCode;
MouseKeyEvent(int enumValue) {
@@ -149,22 +145,19 @@ public class MouseKeysInterceptor extends BaseEventStreamTransformation implemen
* Construct a new MouseKeysInterceptor.
*
* @param service The service to notify of key events
- * @param inputManager InputManager to track changes to connected input devices
* @param looper Looper to use for callbacks and messages
* @param displayId Display ID to send mouse events to
*/
@RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
- public MouseKeysInterceptor(AccessibilityManagerService service, InputManager inputManager,
- Looper looper, int displayId) {
+ public MouseKeysInterceptor(AccessibilityManagerService service, Looper looper, int displayId) {
mAms = service;
- mInputManager = inputManager;
mHandler = new Handler(looper, this);
- mInputManager.registerInputDeviceListener(this, mHandler);
- mDisplayId = displayId;
// Create the virtual mouse on a separate thread since virtual device creation
// should happen on an auxiliary thread, and not from the handler's thread.
+ // This is because virtual device creation is a blocking operation and can cause a
+ // deadlock if it is called from the handler's thread.
new Thread(() -> {
- mVirtualMouse = createVirtualMouse();
+ mVirtualMouse = createVirtualMouse(displayId);
}).start();
}
@@ -193,22 +186,23 @@ public class MouseKeysInterceptor extends BaseEventStreamTransformation implemen
/**
* Performs a mouse scroll action based on the provided key code.
+ * The scroll action will only be performed if the scroll toggle is on.
* This method interprets the key code as a mouse scroll and sends
* the corresponding {@code VirtualMouseScrollEvent#mYAxisMovement}.
* @param keyCode The key code representing the mouse scroll action.
* Supported keys are:
* <ul>
- * <li>{@link MouseKeysInterceptor.MouseKeyEvent SCROLL_UP}
- * <li>{@link MouseKeysInterceptor.MouseKeyEvent SCROLL_DOWN}
+ * <li>{@link MouseKeysInterceptor.MouseKeyEvent#UP_MOVE_OR_SCROLL}
+ * <li>{@link MouseKeysInterceptor.MouseKeyEvent#DOWN_MOVE_OR_SCROLL}
* </ul>
*/
@RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
private void performMouseScrollAction(int keyCode) {
MouseKeyEvent mouseKeyEvent = MouseKeyEvent.from(keyCode);
float y = switch (mouseKeyEvent) {
- case SCROLL_UP -> 1.0f;
- case SCROLL_DOWN -> -1.0f;
+ case UP_MOVE_OR_SCROLL -> 1.0f;
+ case DOWN_MOVE_OR_SCROLL -> -1.0f;
default -> 0.0f;
};
if (mVirtualMouse != null) {
@@ -231,8 +225,8 @@ public class MouseKeysInterceptor extends BaseEventStreamTransformation implemen
* @param keyCode The key code representing the mouse button action.
* Supported keys are:
* <ul>
- * <li>{@link MouseKeysInterceptor.MouseKeyEvent LEFT_CLICK} (Primary Button)
- * <li>{@link MouseKeysInterceptor.MouseKeyEvent RIGHT_CLICK} (Secondary
+ * <li>{@link MouseKeysInterceptor.MouseKeyEvent#LEFT_CLICK} (Primary Button)
+ * <li>{@link MouseKeysInterceptor.MouseKeyEvent#RIGHT_CLICK} (Secondary
* Button)
* </ul>
*/
@@ -264,17 +258,20 @@ public class MouseKeysInterceptor extends BaseEventStreamTransformation implemen
* The method calculates the relative movement of the mouse pointer
* and sends the corresponding event to the virtual mouse.
*
+ * The UP and DOWN pointer actions will only take place for their respective keys
+ * if the scroll toggle is off.
+ *
* @param keyCode The key code representing the direction or button press.
* Supported keys are:
* <ul>
- * <li>{@link MouseKeysInterceptor.MouseKeyEvent DIAGONAL_DOWN_LEFT}
- * <li>{@link MouseKeysInterceptor.MouseKeyEvent DOWN}
- * <li>{@link MouseKeysInterceptor.MouseKeyEvent DIAGONAL_DOWN_RIGHT}
- * <li>{@link MouseKeysInterceptor.MouseKeyEvent LEFT}
- * <li>{@link MouseKeysInterceptor.MouseKeyEvent RIGHT}
- * <li>{@link MouseKeysInterceptor.MouseKeyEvent DIAGONAL_UP_LEFT}
- * <li>{@link MouseKeysInterceptor.MouseKeyEvent UP}
- * <li>{@link MouseKeysInterceptor.MouseKeyEvent DIAGONAL_UP_RIGHT}
+ * <li>{@link MouseKeysInterceptor.MouseKeyEvent#DIAGONAL_DOWN_LEFT_MOVE}
+ * <li>{@link MouseKeysInterceptor.MouseKeyEvent#DOWN_MOVE_OR_SCROLL}
+ * <li>{@link MouseKeysInterceptor.MouseKeyEvent#DIAGONAL_DOWN_RIGHT_MOVE}
+ * <li>{@link MouseKeysInterceptor.MouseKeyEvent#LEFT_MOVE}
+ * <li>{@link MouseKeysInterceptor.MouseKeyEvent#RIGHT_MOVE}
+ * <li>{@link MouseKeysInterceptor.MouseKeyEvent#DIAGONAL_UP_LEFT_MOVE}
+ * <li>{@link MouseKeysInterceptor.MouseKeyEvent#UP_MOVE_OR_SCROLL}
+ * <li>{@link MouseKeysInterceptor.MouseKeyEvent#DIAGONAL_UP_RIGHT_MOVE}
* </ul>
*/
@RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
@@ -287,8 +284,10 @@ public class MouseKeysInterceptor extends BaseEventStreamTransformation implemen
x = -MOUSE_POINTER_MOVEMENT_STEP / sqrt(2);
y = MOUSE_POINTER_MOVEMENT_STEP / sqrt(2);
}
- case DOWN_MOVE -> {
- y = MOUSE_POINTER_MOVEMENT_STEP;
+ case DOWN_MOVE_OR_SCROLL -> {
+ if (!mScrollToggleOn) {
+ y = MOUSE_POINTER_MOVEMENT_STEP;
+ }
}
case DIAGONAL_DOWN_RIGHT_MOVE -> {
x = MOUSE_POINTER_MOVEMENT_STEP / sqrt(2);
@@ -304,8 +303,10 @@ public class MouseKeysInterceptor extends BaseEventStreamTransformation implemen
x = -MOUSE_POINTER_MOVEMENT_STEP / sqrt(2);
y = -MOUSE_POINTER_MOVEMENT_STEP / sqrt(2);
}
- case UP_MOVE -> {
- y = -MOUSE_POINTER_MOVEMENT_STEP;
+ case UP_MOVE_OR_SCROLL -> {
+ if (!mScrollToggleOn) {
+ y = -MOUSE_POINTER_MOVEMENT_STEP;
+ }
}
case DIAGONAL_UP_RIGHT_MOVE -> {
x = MOUSE_POINTER_MOVEMENT_STEP / sqrt(2);
@@ -333,8 +334,8 @@ public class MouseKeysInterceptor extends BaseEventStreamTransformation implemen
}
private boolean isMouseScrollKey(int keyCode) {
- return keyCode == MouseKeyEvent.SCROLL_UP.getKeyCodeValue()
- || keyCode == MouseKeyEvent.SCROLL_DOWN.getKeyCodeValue();
+ return keyCode == MouseKeyEvent.UP_MOVE_OR_SCROLL.getKeyCodeValue()
+ || keyCode == MouseKeyEvent.DOWN_MOVE_OR_SCROLL.getKeyCodeValue();
}
/**
@@ -343,7 +344,7 @@ public class MouseKeysInterceptor extends BaseEventStreamTransformation implemen
* @return The created VirtualMouse.
*/
@RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
- private VirtualMouse createVirtualMouse() {
+ private VirtualMouse createVirtualMouse(int displayId) {
final VirtualDeviceManagerInternal localVdm =
LocalServices.getService(VirtualDeviceManagerInternal.class);
mVirtualDevice = localVdm.createVirtualDevice(
@@ -351,7 +352,7 @@ public class MouseKeysInterceptor extends BaseEventStreamTransformation implemen
VirtualMouse virtualMouse = mVirtualDevice.createVirtualMouse(
new VirtualMouseConfig.Builder()
.setInputDeviceName("Mouse Keys Virtual Mouse")
- .setAssociatedDisplayId(mDisplayId)
+ .setAssociatedDisplayId(displayId)
.build());
return virtualMouse;
}
@@ -375,42 +376,56 @@ public class MouseKeysInterceptor extends BaseEventStreamTransformation implemen
if (!isMouseKey(keyCode)) {
// Pass non-mouse key events to the next handler
super.onKeyEvent(event, policyFlags);
- } else if (keyCode == MouseKeyEvent.HOLD.getKeyCodeValue()) {
- sendVirtualMouseButtonEvent(VirtualMouseButtonEvent.BUTTON_PRIMARY,
- VirtualMouseButtonEvent.ACTION_BUTTON_PRESS);
- } else if (keyCode == MouseKeyEvent.RELEASE.getKeyCodeValue()) {
- sendVirtualMouseButtonEvent(VirtualMouseButtonEvent.BUTTON_PRIMARY,
- VirtualMouseButtonEvent.ACTION_BUTTON_RELEASE);
- } else if (isDown && isMouseButtonKey(keyCode)) {
- performMouseButtonAction(keyCode);
- } else if (isDown && isMouseScrollKey(keyCode)) {
- // If the scroll key is pressed down and no other key is active,
- // set it as the active key and send a message to scroll the pointer
- if (mActiveScrollKey == KEY_NOT_SET) {
- mActiveScrollKey = keyCode;
- mLastTimeKeyActionPerformed = event.getDownTime();
- mHandler.sendEmptyMessage(MESSAGE_SCROLL_MOUSE_POINTER);
- }
} else if (isDown) {
- // This is a directional key.
- // If the key is pressed down and no other key is active,
- // set it as the active key and send a message to move the pointer
- if (mActiveMoveKey == KEY_NOT_SET) {
- mActiveMoveKey = keyCode;
- mLastTimeKeyActionPerformed = event.getDownTime();
- mHandler.sendEmptyMessage(MESSAGE_MOVE_MOUSE_POINTER);
+ if (keyCode == MouseKeyEvent.SCROLL_TOGGLE.getKeyCodeValue()) {
+ mScrollToggleOn = !mScrollToggleOn;
+ if (DEBUG) {
+ Slog.d(LOG_TAG, "Scroll toggle " + (mScrollToggleOn ? "ON" : "OFF"));
+ }
+ } else if (keyCode == MouseKeyEvent.HOLD.getKeyCodeValue()) {
+ sendVirtualMouseButtonEvent(
+ VirtualMouseButtonEvent.BUTTON_PRIMARY,
+ VirtualMouseButtonEvent.ACTION_BUTTON_PRESS
+ );
+ } else if (keyCode == MouseKeyEvent.RELEASE.getKeyCodeValue()) {
+ sendVirtualMouseButtonEvent(
+ VirtualMouseButtonEvent.BUTTON_PRIMARY,
+ VirtualMouseButtonEvent.ACTION_BUTTON_RELEASE
+ );
+ } else if (isMouseButtonKey(keyCode)) {
+ performMouseButtonAction(keyCode);
+ } else if (mScrollToggleOn && isMouseScrollKey(keyCode)) {
+ // If the scroll key is pressed down and no other key is active,
+ // set it as the active key and send a message to scroll the pointer
+ if (mActiveScrollKey == KEY_NOT_SET) {
+ mActiveScrollKey = keyCode;
+ mLastTimeKeyActionPerformed = event.getDownTime();
+ mHandler.sendEmptyMessage(MESSAGE_SCROLL_MOUSE_POINTER);
+ }
+ } else {
+ // This is a directional key.
+ // If the key is pressed down and no other key is active,
+ // set it as the active key and send a message to move the pointer
+ if (mActiveMoveKey == KEY_NOT_SET) {
+ mActiveMoveKey = keyCode;
+ mLastTimeKeyActionPerformed = event.getDownTime();
+ mHandler.sendEmptyMessage(MESSAGE_MOVE_MOUSE_POINTER);
+ }
}
- } else if (mActiveMoveKey == keyCode) {
- // If the key is released, and it is the active key, stop moving the pointer
- mActiveMoveKey = KEY_NOT_SET;
- mHandler.removeMessages(MESSAGE_MOVE_MOUSE_POINTER);
- } else if (mActiveScrollKey == keyCode) {
- // If the key is released, and it is the active key, stop scrolling the pointer
- mActiveScrollKey = KEY_NOT_SET;
- mHandler.removeMessages(MESSAGE_SCROLL_MOUSE_POINTER);
} else {
- Slog.i(LOG_TAG, "Dropping event with key code: '" + keyCode
- + "', with no matching down event from deviceId = " + event.getDeviceId());
+ // Up event received
+ if (mActiveMoveKey == keyCode) {
+ // If the key is released, and it is the active key, stop moving the pointer
+ mActiveMoveKey = KEY_NOT_SET;
+ mHandler.removeMessages(MESSAGE_MOVE_MOUSE_POINTER);
+ } else if (mActiveScrollKey == keyCode) {
+ // If the key is released, and it is the active key, stop scrolling the pointer
+ mActiveScrollKey = KEY_NOT_SET;
+ mHandler.removeMessages(MESSAGE_SCROLL_MOUSE_POINTER);
+ } else {
+ Slog.i(LOG_TAG, "Dropping event with key code: '" + keyCode
+ + "', with no matching down event from deviceId = " + event.getDeviceId());
+ }
}
}
@@ -470,14 +485,6 @@ public class MouseKeysInterceptor extends BaseEventStreamTransformation implemen
}
}
- @Override
- public void onInputDeviceAdded(int deviceId) {
- }
-
- @Override
- public void onInputDeviceRemoved(int deviceId) {
- }
-
@RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
@Override
public void onDestroy() {
@@ -485,14 +492,8 @@ public class MouseKeysInterceptor extends BaseEventStreamTransformation implemen
mActiveMoveKey = KEY_NOT_SET;
mActiveScrollKey = KEY_NOT_SET;
mLastTimeKeyActionPerformed = 0;
- mHandler.removeCallbacksAndMessages(null);
+ mHandler.removeCallbacksAndMessages(null);
mVirtualDevice.close();
- mInputManager.unregisterInputDeviceListener(this);
}
-
- @Override
- public void onInputDeviceChanged(int deviceId) {
- }
-
}
diff --git a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
index 2e9a4dcb45aa..a10039f9bf6c 100644
--- a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
+++ b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
@@ -462,7 +462,9 @@ public final class AutoFillUI {
@Override
public void onShown() {
- mCallback.onShown(UI_TYPE_DIALOG, response.getDatasets().size());
+ if (mCallback != null) {
+ mCallback.onShown(UI_TYPE_DIALOG, response.getDatasets().size());
+ }
}
@Override
@@ -511,7 +513,9 @@ public final class AutoFillUI {
@Override
public void startIntentSender(IntentSender intentSender) {
- mCallback.startIntentSenderAndFinishSession(intentSender);
+ if (mCallback != null) {
+ mCallback.startIntentSenderAndFinishSession(intentSender);
+ }
}
private void log(int type) {
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 1cd20ed0f7cd..9d4310c21cf9 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -215,6 +215,7 @@ java_library_static {
"power_hint_flags_lib",
"biometrics_flags_lib",
"am_flags_lib",
+ "updates_flags_lib",
"com_android_server_accessibility_flags_lib",
"//frameworks/libs/systemui:com_android_systemui_shared_flags_lib",
"com_android_wm_shell_flags_lib",
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index bacfd8f9960e..3633d0f9dd6f 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -2989,7 +2989,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
// Always redact location info from PhysicalChannelConfig if the registrant is from neither
// PHONE nor SYSTEM process. There is no user case that the registrant needs the location
// info (e.g. physicalCellId). This also remove the need for the location permissions check.
- return record.callerUid != Process.PHONE_UID && record.callerUid != Process.SYSTEM_UID;
+ return !TelephonyPermissions.isSystemOrPhone(record.callerUid);
}
/**
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index 21947bac137b..95dbaae2c43b 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -1016,6 +1016,7 @@ public class Watchdog implements Dumpable {
// Trigger the kernel to dump all blocked threads, and backtraces on all CPUs to the
// kernel log
doSysRq('w');
+ doSysRq('m');
doSysRq('l');
}
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index ac9ed0da95a5..458749d93e0a 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -1233,6 +1233,10 @@ public class AccountManagerService
obsoleteAuthType.add(type);
// And delete it from the TABLE_META
accountsDb.deleteMetaByAuthTypeAndUid(type, uid);
+ } else if (knownUid != null && knownUid != uid) {
+ Slog.w(TAG, "authenticator no longer exist for type " + type);
+ obsoleteAuthType.add(type);
+ accountsDb.deleteMetaByAuthTypeAndUid(type, uid);
}
}
}
@@ -5048,6 +5052,9 @@ public class AccountManagerService
if (resolveInfo == null) {
return false;
}
+ if ("content".equals(intent.getScheme())) {
+ return false;
+ }
ActivityInfo targetActivityInfo = resolveInfo.activityInfo;
int targetUid = targetActivityInfo.applicationInfo.uid;
PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 25fb729e7e7c..69ee8fc831f4 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -72,6 +72,7 @@ import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.content.pm.PackageManager.SIGNATURE_NO_MATCH;
+import static android.crashrecovery.flags.Flags.refactorCrashrecovery;
import static android.net.ConnectivityManager.BLOCKED_REASON_NONE;
import static android.os.FactoryTest.FACTORY_TEST_OFF;
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL;
@@ -2075,7 +2076,8 @@ public class ActivityManagerService extends IActivityManager.Stub
app.setPersistent(true);
app.setPid(MY_PID);
app.mState.setMaxAdj(ProcessList.SYSTEM_ADJ);
- app.makeActive(mSystemThread.getApplicationThread(), mProcessStats);
+ app.makeActive(new ApplicationThreadDeferred(mSystemThread.getApplicationThread()),
+ mProcessStats);
app.mProfile.addHostingComponentType(HOSTING_COMPONENT_TYPE_SYSTEM);
addPidLocked(app);
updateLruProcessLocked(app, false, null);
@@ -2322,7 +2324,9 @@ public class ActivityManagerService extends IActivityManager.Stub
} else if (phase == PHASE_ACTIVITY_MANAGER_READY) {
mService.startBroadcastObservers();
} else if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
- mService.mPackageWatchdog.onPackagesReady();
+ if (!refactorCrashrecovery()) {
+ mService.mPackageWatchdog.onPackagesReady();
+ }
mService.scheduleHomeTimeout();
}
}
@@ -4871,7 +4875,7 @@ public class ActivityManagerService extends IActivityManager.Stub
// Make app active after binding application or client may be running requests (e.g
// starting activities) before it is ready.
synchronized (mProcLock) {
- app.makeActive(thread, mProcessStats);
+ app.makeActive(new ApplicationThreadDeferred(thread), mProcessStats);
checkTime(startTime, "attachApplicationLocked: immediately after bindApplication");
}
app.setPendingFinishAttach(true);
diff --git a/services/core/java/com/android/server/am/ApplicationThreadDeferred.java b/services/core/java/com/android/server/am/ApplicationThreadDeferred.java
new file mode 100644
index 000000000000..b0f9b53ff525
--- /dev/null
+++ b/services/core/java/com/android/server/am/ApplicationThreadDeferred.java
@@ -0,0 +1,173 @@
+/*
+ * 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.am;
+
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+
+import android.annotation.IntDef;
+import android.app.IApplicationThread;
+import android.os.RemoteException;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Arrays;
+
+/**
+ * A subclass of {@link IApplicationThread} that defers certain binder calls while the process is
+ * paused (frozen). Any deferred calls are executed when the process is unpaused. In some cases,
+ * multiple instances of deferred calls are collapsed into a single call when the process is
+ * unpaused.
+ *
+ * {@hide}
+ */
+class ApplicationThreadDeferred extends ApplicationThreadFilter {
+
+ static final String TAG = TAG_WITH_CLASS_NAME ? "ApplicationThreadDeferred" : TAG_AM;
+
+ // The flag that enables the deferral behavior of this class. If the flag is disabled then
+ // the class behaves exactly like an ApplicationThreadFilter.
+ private static boolean deferBindersWhenPaused() {
+ return Flags.deferBindersWhenPaused();
+ }
+
+ // The list of notifications that may be deferred.
+ private static final int CLEAR_DNS_CACHE = 0;
+ private static final int UPDATE_TIME_ZONE = 1;
+ private static final int SCHEDULE_LOW_MEMORY = 2;
+ private static final int UPDATE_HTTP_PROXY = 3;
+ private static final int NOTIFICATION_COUNT = 4;
+
+ @IntDef(value = {
+ CLEAR_DNS_CACHE,
+ UPDATE_TIME_ZONE,
+ SCHEDULE_LOW_MEMORY,
+ UPDATE_HTTP_PROXY
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ private @interface NotificationType {};
+
+ private final Object mLock = new Object();
+
+ // If this is true, notifications should be queued for later delivery. If this is false,
+ // notifications should be delivered immediately.
+ @GuardedBy("mLock")
+ private boolean mPaused = false;
+
+ // An operation is a lambda that throws an exception.
+ private interface Operation {
+ void run() throws RemoteException;
+ }
+
+ // The array of operations.
+ @GuardedBy("mLock")
+ private final Operation[] mOperations = new Operation[NOTIFICATION_COUNT];
+
+ // The array of operations that actually pending right now.
+ @GuardedBy("mLock")
+ private final boolean[] mPending = new boolean[NOTIFICATION_COUNT];
+
+ // When true, binder calls to paused processes will be deferred until the process is unpaused.
+ private final boolean mDefer;
+
+ /** Create an instance with a base thread and a deferral enable flag. */
+ @VisibleForTesting
+ public ApplicationThreadDeferred(IApplicationThread thread, boolean defer) {
+ super(thread);
+
+ mDefer = defer;
+
+ mOperations[CLEAR_DNS_CACHE] = () -> { super.clearDnsCache(); };
+ mOperations[UPDATE_TIME_ZONE] = () -> { super.updateTimeZone(); };
+ mOperations[SCHEDULE_LOW_MEMORY] = () -> { super.scheduleLowMemory(); };
+ mOperations[UPDATE_HTTP_PROXY] = () -> { super.updateHttpProxy(); };
+ }
+
+ /** Create an instance with a base flag, using the system deferral enable flag. */
+ public ApplicationThreadDeferred(IApplicationThread thread) {
+ this(thread, deferBindersWhenPaused());
+ }
+
+ /** The process is being paused. Start deferring calls. */
+ void onProcessPaused() {
+ synchronized (mLock) {
+ mPaused = true;
+ }
+ }
+
+ /** The process is no longer paused. Drain any deferred calls. */
+ void onProcessUnpaused() {
+ synchronized (mLock) {
+ mPaused = false;
+ try {
+ for (int i = 0; i < mOperations.length; i++) {
+ if (mPending[i]) {
+ mOperations[i].run();
+ }
+ }
+ } catch (RemoteException e) {
+ // Swallow the exception. The caller is not expecting it. Remote exceptions
+ // happen if a has process died; there is no need to report it here.
+ } finally {
+ Arrays.fill(mPending, false);
+ }
+ }
+ }
+
+ /** The pause operation has been canceled. Drain any deferred calls. */
+ void onProcessPausedCancelled() {
+ onProcessUnpaused();
+ }
+
+ /**
+ * If the thread is not paused, execute the operation. Otherwise, save it to the pending
+ * list.
+ */
+ private void execute(@NotificationType int tag) throws RemoteException {
+ synchronized (mLock) {
+ if (mPaused && mDefer) {
+ mPending[tag] = true;
+ return;
+ }
+ }
+ // Outside the synchronization block to avoid contention.
+ mOperations[tag].run();
+ }
+
+ @Override
+ public void clearDnsCache() throws RemoteException {
+ execute(CLEAR_DNS_CACHE);
+ }
+
+ @Override
+ public void updateTimeZone() throws RemoteException {
+ execute(UPDATE_TIME_ZONE);
+ }
+
+ @Override
+ public void scheduleLowMemory() throws RemoteException {
+ execute(SCHEDULE_LOW_MEMORY);
+ }
+
+ @Override
+ public void updateHttpProxy() throws RemoteException {
+ execute(UPDATE_HTTP_PROXY);
+ }
+}
diff --git a/services/core/java/com/android/server/am/ApplicationThreadFilter.java b/services/core/java/com/android/server/am/ApplicationThreadFilter.java
new file mode 100644
index 000000000000..d049305025c2
--- /dev/null
+++ b/services/core/java/com/android/server/am/ApplicationThreadFilter.java
@@ -0,0 +1,603 @@
+/*
+ * 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.am;
+
+
+class ApplicationThreadFilter implements android.app.IApplicationThread {
+ private final android.app.IApplicationThread mBase;
+ public ApplicationThreadFilter(android.app.IApplicationThread base) { mBase = base; }
+ android.app.IApplicationThread getBase() { return mBase; }
+ public android.os.IBinder asBinder() {
+ return mBase.asBinder();
+ }
+
+ @Override
+ public void scheduleReceiver(android.content.Intent intent,
+ android.content.pm.ActivityInfo info,
+ android.content.res.CompatibilityInfo compatInfo,
+ int resultCode,
+ String data,
+ android.os.Bundle extras,
+ boolean ordered,
+ boolean assumeDelivered,
+ int sendingUser,
+ int processState,
+ int sentFromUid,
+ String sentFromPackage)
+ throws android.os.RemoteException {
+ mBase.scheduleReceiver(intent,
+ info,
+ compatInfo,
+ resultCode,
+ data,
+ extras,
+ ordered,
+ assumeDelivered,
+ sendingUser,
+ processState,
+ sentFromUid,
+ sentFromPackage);
+ }
+ @Override
+ public void scheduleReceiverList(java.util.List<android.app.ReceiverInfo> info)
+ throws android.os.RemoteException {
+ mBase.scheduleReceiverList(info);
+ }
+ @Override
+ public void scheduleCreateService(android.os.IBinder token,
+ android.content.pm.ServiceInfo info,
+ android.content.res.CompatibilityInfo compatInfo,
+ int processState)
+ throws android.os.RemoteException {
+ mBase.scheduleCreateService(token,
+ info,
+ compatInfo,
+ processState);
+ }
+ @Override
+ public void scheduleStopService(android.os.IBinder token)
+ throws android.os.RemoteException {
+ mBase.scheduleStopService(token);
+ }
+ @Override
+ public void bindApplication(String packageName,
+ android.content.pm.ApplicationInfo info,
+ String sdkSandboxClientAppVolumeUuid,
+ String sdkSandboxClientAppPackage,
+ boolean isSdkInSandbox,
+ android.content.pm.ProviderInfoList providerList,
+ android.content.ComponentName testName,
+ android.app.ProfilerInfo profilerInfo,
+ android.os.Bundle testArguments,
+ android.app.IInstrumentationWatcher testWatcher,
+ android.app.IUiAutomationConnection uiAutomationConnection,
+ int debugMode,
+ boolean enableBinderTracking,
+ boolean trackAllocation,
+ boolean restrictedBackupMode,
+ boolean persistent,
+ android.content.res.Configuration config,
+ android.content.res.CompatibilityInfo compatInfo,
+ java.util.Map services,
+ android.os.Bundle coreSettings,
+ String buildSerial,
+ android.content.AutofillOptions autofillOptions,
+ android.content.ContentCaptureOptions contentCaptureOptions,
+ long[] disabledCompatChanges,
+ long[] loggableCompatChanges,
+ android.os.SharedMemory serializedSystemFontMap,
+ long startRequestedElapsedTime,
+ long startRequestedUptime)
+ throws android.os.RemoteException {
+ mBase.bindApplication(packageName,
+ info,
+ sdkSandboxClientAppVolumeUuid,
+ sdkSandboxClientAppPackage,
+ isSdkInSandbox,
+ providerList,
+ testName,
+ profilerInfo,
+ testArguments,
+ testWatcher,
+ uiAutomationConnection,
+ debugMode,
+ enableBinderTracking,
+ trackAllocation,
+ restrictedBackupMode,
+ persistent,
+ config,
+ compatInfo,
+ services,
+ coreSettings,
+ buildSerial,
+ autofillOptions,
+ contentCaptureOptions,
+ disabledCompatChanges,
+ loggableCompatChanges,
+ serializedSystemFontMap,
+ startRequestedElapsedTime,
+ startRequestedUptime);
+ }
+ @Override
+ public void runIsolatedEntryPoint(String entryPoint,
+ String[] entryPointArgs)
+ throws android.os.RemoteException {
+ mBase.runIsolatedEntryPoint(entryPoint,
+ entryPointArgs);
+ }
+ @Override
+ public void scheduleExit()
+ throws android.os.RemoteException {
+ mBase.scheduleExit();
+ }
+ @Override
+ public void scheduleServiceArgs(android.os.IBinder token,
+ android.content.pm.ParceledListSlice args)
+ throws android.os.RemoteException {
+ mBase.scheduleServiceArgs(token,
+ args);
+ }
+ @Override
+ public void updateTimeZone()
+ throws android.os.RemoteException {
+ mBase.updateTimeZone();
+ }
+ @Override
+ public void processInBackground()
+ throws android.os.RemoteException {
+ mBase.processInBackground();
+ }
+ @Override
+ public void scheduleBindService(android.os.IBinder token,
+ android.content.Intent intent,
+ boolean rebind,
+ int processState,
+ long bindSeq)
+ throws android.os.RemoteException {
+ mBase.scheduleBindService(token,
+ intent,
+ rebind,
+ processState,
+ bindSeq);
+ }
+ @Override
+ public void scheduleUnbindService(android.os.IBinder token,
+ android.content.Intent intent)
+ throws android.os.RemoteException {
+ mBase.scheduleUnbindService(token,
+ intent);
+ }
+ @Override
+ public void dumpService(android.os.ParcelFileDescriptor fd,
+ android.os.IBinder servicetoken,
+ String[] args)
+ throws android.os.RemoteException {
+ mBase.dumpService(fd,
+ servicetoken,
+ args);
+ }
+ @Override
+ public void scheduleRegisteredReceiver(android.content.IIntentReceiver receiver,
+ android.content.Intent intent,
+ int resultCode,
+ String data,
+ android.os.Bundle extras,
+ boolean ordered,
+ boolean sticky,
+ boolean assumeDelivered,
+ int sendingUser,
+ int processState,
+ int sentFromUid,
+ String sentFromPackage)
+ throws android.os.RemoteException {
+ mBase.scheduleRegisteredReceiver(receiver,
+ intent,
+ resultCode,
+ data,
+ extras,
+ ordered,
+ sticky,
+ assumeDelivered,
+ sendingUser,
+ processState,
+ sentFromUid,
+ sentFromPackage);
+ }
+ @Override
+ public void scheduleLowMemory()
+ throws android.os.RemoteException {
+ mBase.scheduleLowMemory();
+ }
+ @Override
+ public void profilerControl(boolean start,
+ android.app.ProfilerInfo profilerInfo,
+ int profileType)
+ throws android.os.RemoteException {
+ mBase.profilerControl(start,
+ profilerInfo,
+ profileType);
+ }
+ @Override
+ public void setSchedulingGroup(int group)
+ throws android.os.RemoteException {
+ mBase.setSchedulingGroup(group);
+ }
+ @Override
+ public void scheduleCreateBackupAgent(android.content.pm.ApplicationInfo app,
+ int backupMode,
+ int userId,
+ int operationType)
+ throws android.os.RemoteException {
+ mBase.scheduleCreateBackupAgent(app,
+ backupMode,
+ userId,
+ operationType);
+ }
+ @Override
+ public void scheduleDestroyBackupAgent(android.content.pm.ApplicationInfo app,
+ int userId)
+ throws android.os.RemoteException {
+ mBase.scheduleDestroyBackupAgent(app,
+ userId);
+ }
+ @Override
+ public void scheduleOnNewSceneTransitionInfo(android.os.IBinder token,
+ android.app.ActivityOptions.SceneTransitionInfo info)
+ throws android.os.RemoteException {
+ mBase.scheduleOnNewSceneTransitionInfo(token,
+ info);
+ }
+ @Override
+ public void scheduleSuicide()
+ throws android.os.RemoteException {
+ mBase.scheduleSuicide();
+ }
+ @Override
+ public void dispatchPackageBroadcast(int cmd,
+ String[] packages)
+ throws android.os.RemoteException {
+ mBase.dispatchPackageBroadcast(cmd,
+ packages);
+ }
+ @Override
+ public void scheduleCrash(String msg,
+ int typeId,
+ android.os.Bundle extras)
+ throws android.os.RemoteException {
+ mBase.scheduleCrash(msg,
+ typeId,
+ extras);
+ }
+ @Override
+ public void dumpHeap(boolean managed,
+ boolean mallocInfo,
+ boolean runGc,
+ String dumpBitmaps,
+ String path,
+ android.os.ParcelFileDescriptor fd,
+ android.os.RemoteCallback finishCallback)
+ throws android.os.RemoteException {
+ mBase.dumpHeap(managed,
+ mallocInfo,
+ runGc,
+ dumpBitmaps,
+ path,
+ fd,
+ finishCallback);
+ }
+ @Override
+ public void dumpActivity(android.os.ParcelFileDescriptor fd,
+ android.os.IBinder servicetoken,
+ String prefix,
+ String[] args)
+ throws android.os.RemoteException {
+ mBase.dumpActivity(fd,
+ servicetoken,
+ prefix,
+ args);
+ }
+ @Override
+ public void dumpResources(android.os.ParcelFileDescriptor fd,
+ android.os.RemoteCallback finishCallback)
+ throws android.os.RemoteException {
+ mBase.dumpResources(fd,
+ finishCallback);
+ }
+ @Override
+ public void clearDnsCache()
+ throws android.os.RemoteException {
+ mBase.clearDnsCache();
+ }
+ @Override
+ public void updateHttpProxy()
+ throws android.os.RemoteException {
+ mBase.updateHttpProxy();
+ }
+ @Override
+ public void setCoreSettings(android.os.Bundle coreSettings)
+ throws android.os.RemoteException {
+ mBase.setCoreSettings(coreSettings);
+ }
+ @Override
+ public void updatePackageCompatibilityInfo(String pkg,
+ android.content.res.CompatibilityInfo info)
+ throws android.os.RemoteException {
+ mBase.updatePackageCompatibilityInfo(pkg,
+ info);
+ }
+ @Override
+ public void scheduleTrimMemory(int level)
+ throws android.os.RemoteException {
+ mBase.scheduleTrimMemory(level);
+ }
+ @Override
+ public void dumpMemInfo(android.os.ParcelFileDescriptor fd,
+ android.os.Debug.MemoryInfo mem,
+ boolean checkin,
+ boolean dumpInfo,
+ boolean dumpDalvik,
+ boolean dumpSummaryOnly,
+ boolean dumpUnreachable,
+ boolean dumpAllocatorLogs,
+ String[] args)
+ throws android.os.RemoteException {
+ mBase.dumpMemInfo(fd,
+ mem,
+ checkin,
+ dumpInfo,
+ dumpDalvik,
+ dumpSummaryOnly,
+ dumpUnreachable,
+ dumpAllocatorLogs,
+ args);
+ }
+ @Override
+ public void dumpMemInfoProto(android.os.ParcelFileDescriptor fd,
+ android.os.Debug.MemoryInfo mem,
+ boolean dumpInfo,
+ boolean dumpDalvik,
+ boolean dumpSummaryOnly,
+ boolean dumpUnreachable,
+ String[] args)
+ throws android.os.RemoteException {
+ mBase.dumpMemInfoProto(fd,
+ mem,
+ dumpInfo,
+ dumpDalvik,
+ dumpSummaryOnly,
+ dumpUnreachable,
+ args);
+ }
+ @Override
+ public void dumpGfxInfo(android.os.ParcelFileDescriptor fd,
+ String[] args)
+ throws android.os.RemoteException {
+ mBase.dumpGfxInfo(fd,
+ args);
+ }
+ @Override
+ public void dumpCacheInfo(android.os.ParcelFileDescriptor fd,
+ String[] args)
+ throws android.os.RemoteException {
+ mBase.dumpCacheInfo(fd,
+ args);
+ }
+ @Override
+ public void dumpProvider(android.os.ParcelFileDescriptor fd,
+ android.os.IBinder servicetoken,
+ String[] args)
+ throws android.os.RemoteException {
+ mBase.dumpProvider(fd,
+ servicetoken,
+ args);
+ }
+ @Override
+ public void dumpDbInfo(android.os.ParcelFileDescriptor fd,
+ String[] args)
+ throws android.os.RemoteException {
+ mBase.dumpDbInfo(fd,
+ args);
+ }
+ @Override
+ public void unstableProviderDied(android.os.IBinder provider)
+ throws android.os.RemoteException {
+ mBase.unstableProviderDied(provider);
+ }
+ @Override
+ public void requestAssistContextExtras(android.os.IBinder activityToken,
+ android.os.IBinder requestToken,
+ int requestType,
+ int sessionId,
+ int flags)
+ throws android.os.RemoteException {
+ mBase.requestAssistContextExtras(activityToken,
+ requestToken,
+ requestType,
+ sessionId,
+ flags);
+ }
+ @Override
+ public void scheduleTranslucentConversionComplete(android.os.IBinder token,
+ boolean timeout)
+ throws android.os.RemoteException {
+ mBase.scheduleTranslucentConversionComplete(token,
+ timeout);
+ }
+ @Override
+ public void setProcessState(int state)
+ throws android.os.RemoteException {
+ mBase.setProcessState(state);
+ }
+ @Override
+ public void scheduleInstallProvider(android.content.pm.ProviderInfo provider)
+ throws android.os.RemoteException {
+ mBase.scheduleInstallProvider(provider);
+ }
+ @Override
+ public void updateTimePrefs(int timeFormatPreference)
+ throws android.os.RemoteException {
+ mBase.updateTimePrefs(timeFormatPreference);
+ }
+ @Override
+ public void scheduleEnterAnimationComplete(android.os.IBinder token)
+ throws android.os.RemoteException {
+ mBase.scheduleEnterAnimationComplete(token);
+ }
+ @Override
+ public void notifyCleartextNetwork(byte[] firstPacket)
+ throws android.os.RemoteException {
+ mBase.notifyCleartextNetwork(firstPacket);
+ }
+ @Override
+ public void startBinderTracking()
+ throws android.os.RemoteException {
+ mBase.startBinderTracking();
+ }
+ @Override
+ public void stopBinderTrackingAndDump(android.os.ParcelFileDescriptor fd)
+ throws android.os.RemoteException {
+ mBase.stopBinderTrackingAndDump(fd);
+ }
+ @Override
+ public void scheduleLocalVoiceInteractionStarted(android.os.IBinder token,
+ com.android.internal.app.IVoiceInteractor voiceInteractor)
+ throws android.os.RemoteException {
+ mBase.scheduleLocalVoiceInteractionStarted(token,
+ voiceInteractor);
+ }
+ @Override
+ public void handleTrustStorageUpdate()
+ throws android.os.RemoteException {
+ mBase.handleTrustStorageUpdate();
+ }
+ @Override
+ public void attachAgent(String path)
+ throws android.os.RemoteException {
+ mBase.attachAgent(path);
+ }
+ @Override
+ public void attachStartupAgents(String dataDir)
+ throws android.os.RemoteException {
+ mBase.attachStartupAgents(dataDir);
+ }
+ @Override
+ public void scheduleApplicationInfoChanged(android.content.pm.ApplicationInfo ai)
+ throws android.os.RemoteException {
+ mBase.scheduleApplicationInfoChanged(ai);
+ }
+ @Override
+ public void setNetworkBlockSeq(long procStateSeq)
+ throws android.os.RemoteException {
+ mBase.setNetworkBlockSeq(procStateSeq);
+ }
+ @Override
+ public void scheduleTransaction(android.app.servertransaction.ClientTransaction transaction)
+ throws android.os.RemoteException {
+ mBase.scheduleTransaction(transaction);
+ }
+ @Override
+ public void scheduleTaskFragmentTransaction(android.window.ITaskFragmentOrganizer organizer,
+ android.window.TaskFragmentTransaction transaction)
+ throws android.os.RemoteException {
+ mBase.scheduleTaskFragmentTransaction(organizer,
+ transaction);
+ }
+ @Override
+ public void requestDirectActions(android.os.IBinder activityToken,
+ com.android.internal.app.IVoiceInteractor intractor,
+ android.os.RemoteCallback cancellationCallback,
+ android.os.RemoteCallback callback)
+ throws android.os.RemoteException {
+ mBase.requestDirectActions(activityToken,
+ intractor,
+ cancellationCallback,
+ callback);
+ }
+ @Override
+ public void performDirectAction(android.os.IBinder activityToken,
+ String actionId,
+ android.os.Bundle arguments,
+ android.os.RemoteCallback cancellationCallback,
+ android.os.RemoteCallback resultCallback)
+ throws android.os.RemoteException {
+ mBase.performDirectAction(activityToken,
+ actionId,
+ arguments,
+ cancellationCallback,
+ resultCallback);
+ }
+ @Override
+ public void notifyContentProviderPublishStatus(android.app.ContentProviderHolder holder,
+ String authorities,
+ int userId,
+ boolean published)
+ throws android.os.RemoteException {
+ mBase.notifyContentProviderPublishStatus(holder,
+ authorities,
+ userId,
+ published);
+ }
+ @Override
+ public void instrumentWithoutRestart(android.content.ComponentName instrumentationName,
+ android.os.Bundle instrumentationArgs,
+ android.app.IInstrumentationWatcher instrumentationWatcher,
+ android.app.IUiAutomationConnection instrumentationUiConnection,
+ android.content.pm.ApplicationInfo targetInfo)
+ throws android.os.RemoteException {
+ mBase.instrumentWithoutRestart(instrumentationName,
+ instrumentationArgs,
+ instrumentationWatcher,
+ instrumentationUiConnection,
+ targetInfo);
+ }
+ @Override
+ public void updateUiTranslationState(android.os.IBinder activityToken,
+ int state,
+ android.view.translation.TranslationSpec sourceSpec,
+ android.view.translation.TranslationSpec targetSpec,
+ java.util.List<android.view.autofill.AutofillId> viewIds,
+ android.view.translation.UiTranslationSpec uiTranslationSpec)
+ throws android.os.RemoteException {
+ mBase.updateUiTranslationState(activityToken,
+ state,
+ sourceSpec,
+ targetSpec,
+ viewIds,
+ uiTranslationSpec);
+ }
+ @Override
+ public void scheduleTimeoutService(android.os.IBinder token,
+ int startId)
+ throws android.os.RemoteException {
+ mBase.scheduleTimeoutService(token,
+ startId);
+ }
+ @Override
+ public void scheduleTimeoutServiceForType(android.os.IBinder token,
+ int startId,
+ int fgsType)
+ throws android.os.RemoteException {
+ mBase.scheduleTimeoutServiceForType(token,
+ startId,
+ fgsType);
+ }
+ @Override
+ public void schedulePing(android.os.RemoteCallback pong)
+ throws android.os.RemoteException {
+ mBase.schedulePing(pong);
+ }
+}
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index 6433f2c1c25d..1c4ffbb812a4 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -2656,6 +2656,7 @@ public final class CachedAppOptimizer {
// PIDs that run out of async binder buffer when being frozen
ArraySet<Integer> pidsAsync = (mFreezerBinderAsyncThreshold < 0) ? null : new ArraySet<>();
+ Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "binderErrorSync");
for (int i = 0; i < pids.size(); i++) {
int current = pids.get(i);
try {
@@ -2684,6 +2685,7 @@ public final class CachedAppOptimizer {
Slog.w(TAG_AM, "Unable to query binder frozen stats for pid " + current);
}
}
+ Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
// TODO: when kernel binder driver supports, poll the binder status directly.
// Binderfs stats, like other debugfs files, is not a reliable interface. But it's the
@@ -2693,6 +2695,8 @@ public final class CachedAppOptimizer {
if (pidsAsync == null || pidsAsync.size() == 0) {
return;
}
+
+ Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "binderErrorAsync");
new BinderfsStatsReader().handleFreeAsyncSpace(
// Check if the frozen process has pending async calls
pidsAsync::contains,
@@ -2710,5 +2714,6 @@ public final class CachedAppOptimizer {
// Log the error if binderfs stats can't be accesses or correctly parsed
exception -> Slog.e(TAG_AM, "Unable to parse binderfs stats"));
+ Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
}
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index a74c4896dd8c..3e71d003f455 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -151,7 +151,7 @@ class ProcessRecord implements WindowProcessListener {
* (in which case we are in the process of launching the app).
*/
@CompositeRWLock({"mService", "mProcLock"})
- private IApplicationThread mThread;
+ private ApplicationThreadDeferred mThread;
/**
* Instance of {@link #mThread} that will always meet the {@code oneway}
@@ -737,15 +737,15 @@ class ProcessRecord implements WindowProcessListener {
}
@GuardedBy({"mService", "mProcLock"})
- public void makeActive(IApplicationThread thread, ProcessStatsService tracker) {
+ public void makeActive(ApplicationThreadDeferred thread, ProcessStatsService tracker) {
mProfile.onProcessActive(thread, tracker);
mThread = thread;
if (mPid == Process.myPid()) {
- mOnewayThread = new SameProcessApplicationThread(thread, FgThread.getHandler());
+ mOnewayThread = new SameProcessApplicationThread(mThread, FgThread.getHandler());
} else {
- mOnewayThread = thread;
+ mOnewayThread = mThread;
}
- mWindowProcessController.setThread(thread);
+ mWindowProcessController.setThread(mThread);
if (mWindowProcessController.useFifoUiScheduling()) {
mService.mSpecifiedFifoProcesses.add(this);
}
@@ -1436,14 +1436,17 @@ class ProcessRecord implements WindowProcessListener {
void onProcessFrozen() {
mProfile.onProcessFrozen();
+ if (mThread != null) mThread.onProcessPaused();
}
void onProcessUnfrozen() {
+ if (mThread != null) mThread.onProcessUnpaused();
mProfile.onProcessUnfrozen();
mServices.onProcessUnfrozen();
}
void onProcessFrozenCancelled() {
+ if (mThread != null) mThread.onProcessPausedCancelled();
mServices.onProcessFrozenCancelled();
}
diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
index 932b9c0324fa..7f43fae72d60 100644
--- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
@@ -210,6 +210,7 @@ public class SettingsToPropertiesMapper {
"safety_center",
"sensors",
"spoon",
+ "stability",
"statsd",
"system_performance",
"system_sw_touch",
diff --git a/services/core/java/com/android/server/am/flags.aconfig b/services/core/java/com/android/server/am/flags.aconfig
index 9b380ff12e2d..5315167b46eb 100644
--- a/services/core/java/com/android/server/am/flags.aconfig
+++ b/services/core/java/com/android/server/am/flags.aconfig
@@ -163,7 +163,7 @@ flag {
flag {
name: "collect_logcat_on_run_synchronously"
- namespace: "dropbox"
+ namespace: "stability"
description: "Allow logcat collection on synchronous dropbox collection"
bug: "324222683"
is_fixed_read_only: true
@@ -171,8 +171,16 @@ flag {
flag {
name: "enable_dropbox_watchdog_headers"
- namespace: "dropbox"
+ namespace: "stability"
description: "Add watchdog-specific dropbox headers"
bug: "330682397"
is_fixed_read_only: true
}
+
+flag {
+ name: "defer_binders_when_paused"
+ namespace: "system_performance"
+ is_fixed_read_only: true
+ description: "Defer submitting binder calls to paused processes."
+ bug: "327038797"
+}
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index 0de342807df3..57bffa7e5b40 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -470,8 +470,13 @@ public class BtHelper {
if (mBluetoothHeadset == null || mBluetoothHeadsetDevice == null) {
return false;
}
- return mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
- == BluetoothHeadset.STATE_AUDIO_CONNECTED;
+ try {
+ return mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
+ == BluetoothHeadset.STATE_AUDIO_CONNECTED;
+ } catch (Exception e) {
+ Log.e(TAG, "Exception while getting audio state of " + mBluetoothHeadsetDevice, e);
+ }
+ return false;
}
/*package*/ synchronized boolean isBluetoothScoRequestedInternally() {
@@ -1150,12 +1155,16 @@ public class BtHelper {
}
private void checkScoAudioState() {
- if (mBluetoothHeadset != null
- && mBluetoothHeadsetDevice != null
- && mScoAudioState == SCO_STATE_INACTIVE
- && mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
- != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
- mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
+ try {
+ if (mBluetoothHeadset != null
+ && mBluetoothHeadsetDevice != null
+ && mScoAudioState == SCO_STATE_INACTIVE
+ && mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
+ != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
+ mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Exception while getting audio state of " + mBluetoothHeadsetDevice, e);
}
}
diff --git a/services/core/java/com/android/server/crashrecovery/CrashRecoveryModule.java b/services/core/java/com/android/server/crashrecovery/CrashRecoveryModule.java
new file mode 100644
index 000000000000..317c91e9a289
--- /dev/null
+++ b/services/core/java/com/android/server/crashrecovery/CrashRecoveryModule.java
@@ -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.server.crashrecovery;
+
+import android.content.Context;
+
+import com.android.server.PackageWatchdog;
+import com.android.server.RescueParty;
+import com.android.server.SystemService;
+
+
+/** This class encapsulate the lifecycle methods of CrashRecovery module. */
+public class CrashRecoveryModule {
+ private static final String TAG = "CrashRecoveryModule";
+
+ /** Lifecycle definition for CrashRecovery module. */
+ public static class Lifecycle extends SystemService {
+ private Context mSystemContext;
+ private PackageWatchdog mPackageWatchdog;
+
+ public Lifecycle(Context context) {
+ super(context);
+ mSystemContext = context;
+ mPackageWatchdog = PackageWatchdog.getInstance(context);
+ }
+
+ @Override
+ public void onStart() {
+ RescueParty.registerHealthObserver(mSystemContext);
+ mPackageWatchdog.noteBoot();
+ }
+
+ @Override
+ public void onBootPhase(int phase) {
+ if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
+ mPackageWatchdog.onPackagesReady();
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/crashrecovery/TEST_MAPPING b/services/core/java/com/android/server/crashrecovery/TEST_MAPPING
index 4a66bac2e4ec..615db345635c 100644
--- a/services/core/java/com/android/server/crashrecovery/TEST_MAPPING
+++ b/services/core/java/com/android/server/crashrecovery/TEST_MAPPING
@@ -7,6 +7,9 @@
"include-filter": "com.android.server.RescuePartyTest"
}
]
+ },
+ {
+ "name": "CrashRecoveryModuleTests"
}
]
} \ No newline at end of file
diff --git a/services/core/java/com/android/server/display/BrightnessRangeController.java b/services/core/java/com/android/server/display/BrightnessRangeController.java
index 9b37418bb6fe..515e70495f9e 100644
--- a/services/core/java/com/android/server/display/BrightnessRangeController.java
+++ b/services/core/java/com/android/server/display/BrightnessRangeController.java
@@ -22,6 +22,7 @@ import android.os.IBinder;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.display.brightness.clamper.HdrClamper;
+import com.android.server.display.config.HighBrightnessModeData;
import com.android.server.display.feature.DisplayManagerFlags;
import java.io.PrintWriter;
@@ -157,7 +158,7 @@ class BrightnessRangeController {
private void updateHdrClamper(DisplayDeviceInfo info, IBinder token,
DisplayDeviceConfig displayDeviceConfig) {
if (mUseHdrClamper) {
- DisplayDeviceConfig.HighBrightnessModeData hbmData =
+ HighBrightnessModeData hbmData =
displayDeviceConfig.getHighBrightnessModeData();
float minimumHdrPercentOfScreen =
hbmData == null ? -1f : hbmData.minimumHdrPercentOfScreen;
diff --git a/services/core/java/com/android/server/display/DisplayBrightnessState.java b/services/core/java/com/android/server/display/DisplayBrightnessState.java
index 184ae41fe045..222c5a83a551 100644
--- a/services/core/java/com/android/server/display/DisplayBrightnessState.java
+++ b/services/core/java/com/android/server/display/DisplayBrightnessState.java
@@ -29,9 +29,10 @@ import java.util.Objects;
*/
public final class DisplayBrightnessState {
public static final float CUSTOM_ANIMATION_RATE_NOT_SET = -1f;
+ public static final float BRIGHTNESS_NOT_SET = -1f;
private final float mBrightness;
- private final float mSdrBrightness;
+ private final float mHdrBrightness;
private final float mMaxBrightness;
private final float mMinBrightness;
@@ -51,7 +52,7 @@ public final class DisplayBrightnessState {
private DisplayBrightnessState(Builder builder) {
mBrightness = builder.getBrightness();
- mSdrBrightness = builder.getSdrBrightness();
+ mHdrBrightness = builder.getHdrBrightness();
mBrightnessReason = builder.getBrightnessReason();
mDisplayBrightnessStrategyName = builder.getDisplayBrightnessStrategyName();
mShouldUseAutoBrightness = builder.getShouldUseAutoBrightness();
@@ -73,10 +74,10 @@ public final class DisplayBrightnessState {
}
/**
- * Gets the sdr brightness
+ * Gets the hdr brightness
*/
- public float getSdrBrightness() {
- return mSdrBrightness;
+ public float getHdrBrightness() {
+ return mHdrBrightness;
}
/**
@@ -163,8 +164,8 @@ public final class DisplayBrightnessState {
StringBuilder stringBuilder = new StringBuilder("DisplayBrightnessState:");
stringBuilder.append("\n brightness:");
stringBuilder.append(getBrightness());
- stringBuilder.append("\n sdrBrightness:");
- stringBuilder.append(getSdrBrightness());
+ stringBuilder.append("\n hdrBrightness:");
+ stringBuilder.append(getHdrBrightness());
stringBuilder.append("\n brightnessReason:");
stringBuilder.append(getBrightnessReason());
stringBuilder.append("\n shouldUseAutoBrightness:");
@@ -198,7 +199,7 @@ public final class DisplayBrightnessState {
DisplayBrightnessState otherState = (DisplayBrightnessState) other;
return mBrightness == otherState.getBrightness()
- && mSdrBrightness == otherState.getSdrBrightness()
+ && mHdrBrightness == otherState.getHdrBrightness()
&& mBrightnessReason.equals(otherState.getBrightnessReason())
&& TextUtils.equals(mDisplayBrightnessStrategyName,
otherState.getDisplayBrightnessStrategyName())
@@ -216,7 +217,7 @@ public final class DisplayBrightnessState {
@Override
public int hashCode() {
- return Objects.hash(mBrightness, mSdrBrightness, mBrightnessReason,
+ return Objects.hash(mBrightness, mHdrBrightness, mBrightnessReason,
mShouldUseAutoBrightness, mIsSlowChange, mMaxBrightness, mMinBrightness,
mCustomAnimationRate,
mShouldUpdateScreenBrightnessSetting, mBrightnessEvent, mBrightnessAdjustmentFlag,
@@ -235,7 +236,7 @@ public final class DisplayBrightnessState {
*/
public static class Builder {
private float mBrightness;
- private float mSdrBrightness;
+ private float mHdrBrightness = BRIGHTNESS_NOT_SET;
private BrightnessReason mBrightnessReason = new BrightnessReason();
private String mDisplayBrightnessStrategyName;
private boolean mShouldUseAutoBrightness;
@@ -260,7 +261,7 @@ public final class DisplayBrightnessState {
public static Builder from(DisplayBrightnessState state) {
Builder builder = new Builder();
builder.setBrightness(state.getBrightness());
- builder.setSdrBrightness(state.getSdrBrightness());
+ builder.setHdrBrightness(state.getHdrBrightness());
builder.setBrightnessReason(state.getBrightnessReason());
builder.setDisplayBrightnessStrategyName(state.getDisplayBrightnessStrategyName());
builder.setShouldUseAutoBrightness(state.getShouldUseAutoBrightness());
@@ -295,20 +296,20 @@ public final class DisplayBrightnessState {
}
/**
- * Gets the sdr brightness
+ * Gets the hdr brightness
*/
- public float getSdrBrightness() {
- return mSdrBrightness;
+ public float getHdrBrightness() {
+ return mHdrBrightness;
}
/**
- * Sets the sdr brightness
+ * Sets the hdr brightness
*
- * @param sdrBrightness The sdr brightness to be associated with DisplayBrightnessState's
+ * @param hdrBrightness The hdr brightness to be associated with DisplayBrightnessState's
* builder
*/
- public Builder setSdrBrightness(float sdrBrightness) {
- this.mSdrBrightness = sdrBrightness;
+ public Builder setHdrBrightness(float hdrBrightness) {
+ this.mHdrBrightness = hdrBrightness;
return this;
}
diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index e4db634c0e26..f5231ae0abe6 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -53,9 +53,9 @@ import com.android.server.display.config.DisplayBrightnessPoint;
import com.android.server.display.config.DisplayConfiguration;
import com.android.server.display.config.DisplayQuirks;
import com.android.server.display.config.EvenDimmerBrightnessData;
-import com.android.server.display.config.HbmTiming;
import com.android.server.display.config.HdrBrightnessData;
import com.android.server.display.config.HighBrightnessMode;
+import com.android.server.display.config.HighBrightnessModeData;
import com.android.server.display.config.HysteresisLevels;
import com.android.server.display.config.IdleScreenRefreshRateTimeout;
import com.android.server.display.config.IdleScreenRefreshRateTimeoutLuxThresholdPoint;
@@ -75,8 +75,6 @@ import com.android.server.display.config.RefreshRateRange;
import com.android.server.display.config.RefreshRateThrottlingMap;
import com.android.server.display.config.RefreshRateThrottlingPoint;
import com.android.server.display.config.RefreshRateZone;
-import com.android.server.display.config.SdrHdrRatioMap;
-import com.android.server.display.config.SdrHdrRatioPoint;
import com.android.server.display.config.SensorData;
import com.android.server.display.config.ThermalStatus;
import com.android.server.display.config.ThermalThrottling;
@@ -302,6 +300,19 @@ import javax.xml.datatype.DatatypeConfigurationException;
* <brightnessIncreaseDurationMillis>10000</brightnessIncreaseDurationMillis>
* <brightnessDecreaseDebounceMillis>13000</brightnessDecreaseDebounceMillis>
* <brightnessDecreaseDurationMillis>10000</brightnessDecreaseDurationMillis>
+ * <minimumHdrPercentOfScreenForNbm>0.2</minimumHdrPercentOfScreenForNbm>
+ * <minimumHdrPercentOfScreenForHbm>0.5</minimumHdrPercentOfScreenForHbm>
+ * <allowInLowPowerMode>true</allowInLowPowerMode>
+ * <sdrHdrRatioMap>
+ * <point>
+ * <first>2.0</first>
+ * <second>4.0</second>
+ * </point>
+ * <point>
+ * <first>100</first>
+ * <second>8.0</second>
+ * </point>
+ * </sdrHdrRatioMap>
* </hdrBrightnessConfig>
* <luxThrottling>
* <brightnessLimitMap>
@@ -659,9 +670,6 @@ public class DisplayDeviceConfig {
// Invalid value of AutoBrightness brightening and darkening light debounce
private static final int INVALID_AUTO_BRIGHTNESS_LIGHT_DEBOUNCE = -1;
- @VisibleForTesting
- static final float HDR_PERCENT_OF_SCREEN_REQUIRED_DEFAULT = 0.5f;
-
private final Context mContext;
// The details of the ambient light sensor associated with this display.
@@ -743,13 +751,13 @@ public class DisplayDeviceConfig {
private Spline mNitsToBacklightSpline;
private List<String> mQuirks;
- private boolean mIsHighBrightnessModeEnabled = false;
+ @Nullable
private HighBrightnessModeData mHbmData;
@Nullable
private PowerThrottlingConfigData mPowerThrottlingConfigData;
private DensityMapping mDensityMapping;
private String mLoadedFrom = null;
- private Spline mSdrToHdrRatioSpline;
+
// Represents the auto-brightness brightening light debounce.
private long mAutoBrightnessBrighteningLightDebounce =
@@ -872,7 +880,7 @@ public class DisplayDeviceConfig {
private final DisplayManagerFlags mFlags;
@VisibleForTesting
- DisplayDeviceConfig(Context context, DisplayManagerFlags flags) {
+ public DisplayDeviceConfig(Context context, DisplayManagerFlags flags) {
mContext = context;
mFlags = flags;
}
@@ -1155,7 +1163,7 @@ public class DisplayDeviceConfig {
* @return true if there is sdrHdrRatioMap, false otherwise.
*/
public boolean hasSdrToHdrRatioSpline() {
- return mSdrToHdrRatioSpline != null;
+ return mHbmData != null && mHbmData.sdrToHdrRatioSpline != null;
}
/**
@@ -1165,7 +1173,8 @@ public class DisplayDeviceConfig {
* @return the HDR brightness or BRIGHTNESS_INVALID when no mapping exists.
*/
public float getHdrBrightnessFromSdr(float brightness, float maxDesiredHdrSdrRatio) {
- if (mSdrToHdrRatioSpline == null) {
+ Spline sdrToHdrSpline = mHbmData != null ? mHbmData.sdrToHdrRatioSpline : null;
+ if (sdrToHdrSpline == null) {
return PowerManager.BRIGHTNESS_INVALID;
}
@@ -1175,7 +1184,7 @@ public class DisplayDeviceConfig {
return PowerManager.BRIGHTNESS_INVALID;
}
- float ratio = Math.min(mSdrToHdrRatioSpline.interpolate(nits), maxDesiredHdrSdrRatio);
+ float ratio = Math.min(sdrToHdrSpline.interpolate(nits), maxDesiredHdrSdrRatio);
float hdrNits = nits * ratio;
if (getNitsToBacklightSpline() == null) {
return PowerManager.BRIGHTNESS_INVALID;
@@ -1321,13 +1330,11 @@ public class DisplayDeviceConfig {
* @return high brightness mode configuration data for the display.
*/
public HighBrightnessModeData getHighBrightnessModeData() {
- if (!mIsHighBrightnessModeEnabled || mHbmData == null) {
+ if (mHbmData == null || !mHbmData.isHighBrightnessModeEnabled) {
return null;
}
- HighBrightnessModeData hbmData = new HighBrightnessModeData();
- mHbmData.copyTo(hbmData);
- return hbmData;
+ return mHbmData;
}
/**
@@ -1604,11 +1611,10 @@ public class DisplayDeviceConfig {
+ ", mBacklightMaximum=" + mBacklightMaximum
+ ", mBrightnessDefault=" + mBrightnessDefault
+ ", mQuirks=" + mQuirks
- + ", mIsHighBrightnessModeEnabled=" + mIsHighBrightnessModeEnabled
+ "\n"
+ "mLuxThrottlingData=" + mLuxThrottlingData
+ ", mHbmData=" + mHbmData
- + ", mSdrToHdrRatioSpline=" + mSdrToHdrRatioSpline
+
+ ", mThermalBrightnessThrottlingDataMapByThrottlingId="
+ mThermalBrightnessThrottlingDataMapByThrottlingId
+ "\n"
@@ -1715,7 +1721,7 @@ public class DisplayDeviceConfig {
}
@VisibleForTesting
- boolean initFromFile(File configFile) {
+ public boolean initFromFile(File configFile) {
if (!configFile.exists()) {
// Display configuration files aren't required to exist.
return false;
@@ -1740,7 +1746,23 @@ public class DisplayDeviceConfig {
loadBrightnessMap(config);
loadThermalThrottlingConfig(config);
loadPowerThrottlingConfigData(config);
- loadHighBrightnessModeData(config);
+ // Backlight and evenDimmer data should be loaded for HbmData
+ mHbmData = HighBrightnessModeData.loadHighBrightnessModeData(config, (hbm) -> {
+ float transitionPointBacklightScale = hbm.getTransitionPoint_all().floatValue();
+ if (transitionPointBacklightScale >= mBacklightMaximum) {
+ throw new IllegalArgumentException("HBM transition point invalid. "
+ + mHbmData.transitionPoint + " is not less than "
+ + mBacklightMaximum);
+ }
+ return getBrightnessFromBacklight(transitionPointBacklightScale);
+ });
+ if (mHbmData.isHighBrightnessModeEnabled && mHbmData.refreshRateLimit != null) {
+ // TODO(b/331650248): cleanup, DMD can use mHbmData.refreshRateLimit
+ mRefreshRateLimitations.add(new RefreshRateLimitation(
+ DisplayManagerInternal.REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE,
+ mHbmData.refreshRateLimit));
+ }
+
loadLuxThrottling(config);
loadQuirks(config);
loadBrightnessRamps(config);
@@ -1938,40 +1960,6 @@ public class DisplayDeviceConfig {
constrainNitsAndBacklightArrays();
}
- private Spline loadSdrHdrRatioMap(HighBrightnessMode hbmConfig) {
- final SdrHdrRatioMap sdrHdrRatioMap = hbmConfig.getSdrHdrRatioMap_all();
-
- if (sdrHdrRatioMap == null) {
- return null;
- }
-
- final List<SdrHdrRatioPoint> points = sdrHdrRatioMap.getPoint();
- final int size = points.size();
- if (size == 0) {
- return null;
- }
-
- float[] nits = new float[size];
- float[] ratios = new float[size];
-
- int i = 0;
- for (SdrHdrRatioPoint point : points) {
- nits[i] = point.getSdrNits().floatValue();
- if (i > 0) {
- if (nits[i] < nits[i - 1]) {
- Slog.e(TAG, "sdrHdrRatioMap must be non-decreasing, ignoring rest "
- + " of configuration. nits: " + nits[i] + " < "
- + nits[i - 1]);
- return null;
- }
- }
- ratios[i] = point.getHdrRatio().floatValue();
- ++i;
- }
-
- return Spline.createSpline(nits, ratios);
- }
-
private void loadThermalThrottlingConfig(DisplayConfiguration config) {
final ThermalThrottling throttlingConfig = config.getThermalThrottling();
if (throttlingConfig == null) {
@@ -2525,49 +2513,6 @@ public class DisplayDeviceConfig {
}
}
- private void loadHighBrightnessModeData(DisplayConfiguration config) {
- final HighBrightnessMode hbm = config.getHighBrightnessMode();
- if (hbm != null) {
- mIsHighBrightnessModeEnabled = hbm.getEnabled();
- mHbmData = new HighBrightnessModeData();
- mHbmData.minimumLux = hbm.getMinimumLux_all().floatValue();
- float transitionPointBacklightScale = hbm.getTransitionPoint_all().floatValue();
- if (transitionPointBacklightScale >= mBacklightMaximum) {
- throw new IllegalArgumentException("HBM transition point invalid. "
- + mHbmData.transitionPoint + " is not less than "
- + mBacklightMaximum);
- }
- mHbmData.transitionPoint =
- getBrightnessFromBacklight(transitionPointBacklightScale);
- final HbmTiming hbmTiming = hbm.getTiming_all();
- mHbmData.timeWindowMillis = hbmTiming.getTimeWindowSecs_all().longValue() * 1000;
- mHbmData.timeMaxMillis = hbmTiming.getTimeMaxSecs_all().longValue() * 1000;
- mHbmData.timeMinMillis = hbmTiming.getTimeMinSecs_all().longValue() * 1000;
- mHbmData.allowInLowPowerMode = hbm.getAllowInLowPowerMode_all();
- final RefreshRateRange rr = hbm.getRefreshRate_all();
- if (rr != null) {
- final float min = rr.getMinimum().floatValue();
- final float max = rr.getMaximum().floatValue();
- mRefreshRateLimitations.add(new RefreshRateLimitation(
- DisplayManagerInternal.REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE, min, max));
- }
- BigDecimal minHdrPctOfScreen = hbm.getMinimumHdrPercentOfScreen_all();
- if (minHdrPctOfScreen != null) {
- mHbmData.minimumHdrPercentOfScreen = minHdrPctOfScreen.floatValue();
- if (mHbmData.minimumHdrPercentOfScreen > 1
- || mHbmData.minimumHdrPercentOfScreen < 0) {
- Slog.w(TAG, "Invalid minimum HDR percent of screen: "
- + String.valueOf(mHbmData.minimumHdrPercentOfScreen));
- mHbmData.minimumHdrPercentOfScreen = HDR_PERCENT_OF_SCREEN_REQUIRED_DEFAULT;
- }
- } else {
- mHbmData.minimumHdrPercentOfScreen = HDR_PERCENT_OF_SCREEN_REQUIRED_DEFAULT;
- }
-
- mSdrToHdrRatioSpline = loadSdrHdrRatioMap(hbm);
- }
- }
-
private void loadLuxThrottling(DisplayConfiguration config) {
LuxThrottling cfg = config.getLuxThrottling();
if (cfg != null) {
@@ -2921,73 +2866,6 @@ public class DisplayDeviceConfig {
}
/**
- * Container for high brightness mode configuration data.
- */
- static class HighBrightnessModeData {
- /** Minimum lux needed to enter high brightness mode */
- public float minimumLux;
-
- /** Brightness level at which we transition from normal to high-brightness. */
- public float transitionPoint;
-
- /** Whether HBM is allowed when {@code Settings.Global.LOW_POWER_MODE} is active. */
- public boolean allowInLowPowerMode;
-
- /** Time window for HBM. */
- public long timeWindowMillis;
-
- /** Maximum time HBM is allowed to be during in a {@code timeWindowMillis}. */
- public long timeMaxMillis;
-
- /** Minimum time that HBM can be on before being enabled. */
- public long timeMinMillis;
-
- /** Minimum HDR video size to enter high brightness mode */
- public float minimumHdrPercentOfScreen;
-
- HighBrightnessModeData() {}
-
- HighBrightnessModeData(float minimumLux, float transitionPoint, long timeWindowMillis,
- long timeMaxMillis, long timeMinMillis, boolean allowInLowPowerMode,
- float minimumHdrPercentOfScreen) {
- this.minimumLux = minimumLux;
- this.transitionPoint = transitionPoint;
- this.timeWindowMillis = timeWindowMillis;
- this.timeMaxMillis = timeMaxMillis;
- this.timeMinMillis = timeMinMillis;
- this.allowInLowPowerMode = allowInLowPowerMode;
- this.minimumHdrPercentOfScreen = minimumHdrPercentOfScreen;
- }
-
- /**
- * Copies the HBM data to the specified parameter instance.
- * @param other the instance to copy data to.
- */
- public void copyTo(@NonNull HighBrightnessModeData other) {
- other.minimumLux = minimumLux;
- other.timeWindowMillis = timeWindowMillis;
- other.timeMaxMillis = timeMaxMillis;
- other.timeMinMillis = timeMinMillis;
- other.transitionPoint = transitionPoint;
- other.allowInLowPowerMode = allowInLowPowerMode;
- other.minimumHdrPercentOfScreen = minimumHdrPercentOfScreen;
- }
-
- @Override
- public String toString() {
- return "HBM{"
- + "minLux: " + minimumLux
- + ", transition: " + transitionPoint
- + ", timeWindow: " + timeWindowMillis + "ms"
- + ", timeMax: " + timeMaxMillis + "ms"
- + ", timeMin: " + timeMinMillis + "ms"
- + ", allowInLowPowerMode: " + allowInLowPowerMode
- + ", minimumHdrPercentOfScreen: " + minimumHdrPercentOfScreen
- + "} ";
- }
- }
-
- /**
* Container for Power throttling configuration data.
* TODO(b/302814899): extract to separate class.
*/
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 3493381b3064..2f3584cf7cef 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -5240,7 +5240,7 @@ public final class DisplayManagerService extends SystemService {
mHandler.sendMessage(msg);
mLogicalDisplayMapper
- .setDeviceStateLocked(deviceState.getIdentifier());
+ .setDeviceStateLocked(deviceState);
}
}
};
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 6694ebbe461a..58309c2c751a 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -87,6 +87,7 @@ import com.android.server.display.brightness.strategy.AutomaticBrightnessStrateg
import com.android.server.display.brightness.strategy.DisplayBrightnessStrategyConstants;
import com.android.server.display.color.ColorDisplayService.ColorDisplayServiceInternal;
import com.android.server.display.color.ColorDisplayService.ReduceBrightColorsListener;
+import com.android.server.display.config.HighBrightnessModeData;
import com.android.server.display.config.HysteresisLevels;
import com.android.server.display.feature.DisplayManagerFlags;
import com.android.server.display.layout.Layout;
@@ -1633,9 +1634,13 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
// use instead. We still preserve the calculated brightness for Standard Dynamic Range
// (SDR) layers, but the main brightness value will be the one for HDR.
float sdrAnimateValue = animateValue;
- // TODO(b/216365040): The decision to prevent HBM for HDR in low power mode should be
- // done in HighBrightnessModeController.
- if (mBrightnessRangeController.getHighBrightnessMode()
+
+ if (clampedState.getHdrBrightness() != DisplayBrightnessState.BRIGHTNESS_NOT_SET) {
+ // TODO(b/343792639): The decision to prevent HBM for HDR in low power mode will be
+ // done in HdrBrightnessModifier.
+ // customAnimationRate and reason also handled by HdrBrightnessModifier
+ animateValue = clampedState.getHdrBrightness();
+ } else if (mBrightnessRangeController.getHighBrightnessMode()
== BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR
&& (mBrightnessReasonTemp.getModifier() & BrightnessReason.MODIFIER_DIMMED) == 0
&& (mBrightnessReasonTemp.getModifier() & BrightnessReason.MODIFIER_LOW_POWER)
@@ -2013,7 +2018,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
final DisplayDeviceConfig ddConfig = mDisplayDevice.getDisplayDeviceConfig();
final IBinder displayToken = mDisplayDevice.getDisplayTokenLocked();
final String displayUniqueId = mDisplayDevice.getUniqueId();
- final DisplayDeviceConfig.HighBrightnessModeData hbmData =
+ final HighBrightnessModeData hbmData =
ddConfig != null ? ddConfig.getHighBrightnessModeData() : null;
final DisplayDeviceInfo info = mDisplayDevice.getDisplayDeviceInfoLocked();
return mInjector.getHighBrightnessModeController(mHandler, info.width, info.height,
@@ -3247,7 +3252,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
HighBrightnessModeController getHighBrightnessModeController(Handler handler, int width,
int height, IBinder displayToken, String displayUniqueId, float brightnessMin,
- float brightnessMax, DisplayDeviceConfig.HighBrightnessModeData hbmData,
+ float brightnessMax, HighBrightnessModeData hbmData,
HighBrightnessModeController.HdrBrightnessDeviceConfig hdrBrightnessCfg,
Runnable hbmChangeCallback, HighBrightnessModeMetadata hbmMetadata,
Context context) {
diff --git a/services/core/java/com/android/server/display/HighBrightnessModeController.java b/services/core/java/com/android/server/display/HighBrightnessModeController.java
index 47176fe331bf..da9eef2d7459 100644
--- a/services/core/java/com/android/server/display/HighBrightnessModeController.java
+++ b/services/core/java/com/android/server/display/HighBrightnessModeController.java
@@ -36,8 +36,8 @@ import android.view.SurfaceControlHdrLayerInfoListener;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.display.BrightnessSynchronizer;
import com.android.internal.util.FrameworkStatsLog;
-import com.android.server.display.DisplayDeviceConfig.HighBrightnessModeData;
import com.android.server.display.DisplayManagerService.Clock;
+import com.android.server.display.config.HighBrightnessModeData;
import com.android.server.display.utils.DebugUtils;
import java.io.PrintWriter;
diff --git a/services/core/java/com/android/server/display/LogicalDisplayMapper.java b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
index 4791cd1403e2..d3b41b848583 100644
--- a/services/core/java/com/android/server/display/LogicalDisplayMapper.java
+++ b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
@@ -16,12 +16,17 @@
package com.android.server.display;
+import static android.hardware.devicestate.DeviceState.PROPERTY_POWER_CONFIGURATION_TRIGGER_SLEEP;
+import static android.hardware.devicestate.DeviceState.PROPERTY_POWER_CONFIGURATION_TRIGGER_WAKE;
+import static android.hardware.devicestate.DeviceStateManager.INVALID_DEVICE_STATE;
import static android.view.Display.DEFAULT_DISPLAY;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
-import android.hardware.devicestate.DeviceStateManager;
+import android.hardware.devicestate.DeviceState;
+import android.hardware.devicestate.feature.flags.FeatureFlags;
+import android.hardware.devicestate.feature.flags.FeatureFlagsImpl;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -198,14 +203,14 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
private final DisplayIdProducer mIdProducer = (isDefault) ->
isDefault ? DEFAULT_DISPLAY : sNextNonDefaultDisplayId++;
private Layout mCurrentLayout = null;
- private int mDeviceState = DeviceStateManager.INVALID_DEVICE_STATE_IDENTIFIER;
- private int mPendingDeviceState = DeviceStateManager.INVALID_DEVICE_STATE_IDENTIFIER;
- private int mDeviceStateToBeAppliedAfterBoot =
- DeviceStateManager.INVALID_DEVICE_STATE_IDENTIFIER;
+ private DeviceState mDeviceState = INVALID_DEVICE_STATE;
+ private DeviceState mPendingDeviceState = INVALID_DEVICE_STATE;
+ private DeviceState mDeviceStateToBeAppliedAfterBoot = INVALID_DEVICE_STATE;
private boolean mBootCompleted = false;
private boolean mInteractive;
private final DisplayManagerFlags mFlags;
private final SyntheticModeManager mSyntheticModeManager;
+ private final FeatureFlags mDeviceStateManagerFlags;
LogicalDisplayMapper(@NonNull Context context, FoldSettingProvider foldSettingProvider,
FoldGracePeriodProvider foldGracePeriodProvider,
@@ -245,6 +250,7 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
mDeviceStateToLayoutMap = deviceStateToLayoutMap;
mFlags = flags;
mSyntheticModeManager = syntheticModeManager;
+ mDeviceStateManagerFlags = new FeatureFlagsImpl();
}
@Override
@@ -403,8 +409,8 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
// Retrieve the display info for the display that matches the display id.
final DisplayDevice device = mDisplayDeviceRepo.getByAddressLocked(display.getAddress());
if (device == null) {
- Slog.w(TAG, "The display device (" + display.getAddress() + "), is not available"
- + " for the display state " + mDeviceState);
+ Slog.w(TAG, "The display device (" + display.getAddress()
+ + "), is not available for the display state " + mDeviceState.getIdentifier());
return null;
}
LogicalDisplay logicalDisplay = getDisplayLocked(device, /* includeDisabled= */ true);
@@ -431,9 +437,11 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
ipw.println("mBootCompleted=" + mBootCompleted);
ipw.println();
- ipw.println("mDeviceState=" + mDeviceState);
- ipw.println("mPendingDeviceState=" + mPendingDeviceState);
- ipw.println("mDeviceStateToBeAppliedAfterBoot=" + mDeviceStateToBeAppliedAfterBoot);
+
+ ipw.println("mDeviceState=" + mDeviceState.getIdentifier());
+ ipw.println("mPendingDeviceState=" + mPendingDeviceState.getIdentifier());
+ ipw.println("mDeviceStateToBeAppliedAfterBoot="
+ + mDeviceStateToBeAppliedAfterBoot.getIdentifier());
final int logicalDisplayCount = mLogicalDisplays.size();
ipw.println();
@@ -463,7 +471,7 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
mVirtualDeviceDisplayMapping.put(displayDevice.getUniqueId(), virtualDeviceUniqueId);
}
- void setDeviceStateLocked(int state) {
+ void setDeviceStateLocked(DeviceState state) {
if (!mBootCompleted) {
// The boot animation might still be in progress, we do not want to switch states now
// as the boot animation would end up with an incorrect size.
@@ -475,15 +483,17 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
return;
}
- Slog.i(TAG, "Requesting Transition to state: " + state + ", from state=" + mDeviceState
- + ", interactive=" + mInteractive + ", mBootCompleted=" + mBootCompleted);
+ Slog.i(TAG, "Requesting Transition to state: " + state + ", from state="
+ + mDeviceState.getIdentifier() + ", interactive=" + mInteractive
+ + ", mBootCompleted=" + mBootCompleted);
// As part of a state transition, we may need to turn off some displays temporarily so that
// the transition is smooth. Plus, on some devices, only one internal displays can be
// on at a time. We use LogicalDisplay.setIsInTransition to mark a display that needs to be
// temporarily turned off.
- resetLayoutLocked(mDeviceState, state, /* transitionValue= */ true);
+ resetLayoutLocked(mDeviceState.getIdentifier(),
+ state.getIdentifier(), /* transitionValue= */ true);
mPendingDeviceState = state;
- mDeviceStateToBeAppliedAfterBoot = DeviceStateManager.INVALID_DEVICE_STATE_IDENTIFIER;
+ mDeviceStateToBeAppliedAfterBoot = INVALID_DEVICE_STATE;
final boolean wakeDevice = shouldDeviceBeWoken(mPendingDeviceState, mDeviceState,
mInteractive, mBootCompleted);
final boolean sleepDevice = shouldDeviceBePutToSleep(mPendingDeviceState, mDeviceState,
@@ -498,7 +508,7 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
}
if (DEBUG) {
- Slog.d(TAG, "Postponing transition to state: " + mPendingDeviceState);
+ Slog.d(TAG, "Postponing transition to state: " + mPendingDeviceState.getIdentifier());
}
// Send the transitioning phase updates to DisplayManager so that the displays can
// start turning OFF in preparation for the new layout.
@@ -533,8 +543,7 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
void onBootCompleted() {
synchronized (mSyncRoot) {
mBootCompleted = true;
- if (mDeviceStateToBeAppliedAfterBoot
- != DeviceStateManager.INVALID_DEVICE_STATE_IDENTIFIER) {
+ if (!mDeviceStateToBeAppliedAfterBoot.equals(INVALID_DEVICE_STATE)) {
setDeviceStateLocked(mDeviceStateToBeAppliedAfterBoot);
}
}
@@ -563,11 +572,18 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
* @see #setDeviceStateLocked
*/
@VisibleForTesting
- boolean shouldDeviceBeWoken(int pendingState, int currentState, boolean isInteractive,
- boolean isBootCompleted) {
- return mDeviceStatesOnWhichToWakeUp.get(pendingState)
- && !mDeviceStatesOnWhichToWakeUp.get(currentState)
- && !isInteractive && isBootCompleted;
+ boolean shouldDeviceBeWoken(DeviceState pendingState, DeviceState currentState,
+ boolean isInteractive, boolean isBootCompleted) {
+ if (mDeviceStateManagerFlags.deviceStatePropertyMigration()) {
+ return pendingState.hasProperty(PROPERTY_POWER_CONFIGURATION_TRIGGER_WAKE)
+ && !currentState.equals(INVALID_DEVICE_STATE)
+ && !currentState.hasProperty(PROPERTY_POWER_CONFIGURATION_TRIGGER_WAKE)
+ && !isInteractive && isBootCompleted;
+ } else {
+ return mDeviceStatesOnWhichToWakeUp.get(pendingState.getIdentifier())
+ && !mDeviceStatesOnWhichToWakeUp.get(currentState.getIdentifier())
+ && !isInteractive && isBootCompleted;
+ }
}
/**
@@ -588,14 +604,22 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
* @see #setDeviceStateLocked
*/
@VisibleForTesting
- boolean shouldDeviceBePutToSleep(int pendingState, int currentState, boolean isInteractive,
- boolean isBootCompleted) {
- return currentState != DeviceStateManager.INVALID_DEVICE_STATE_IDENTIFIER
- && mDeviceStatesOnWhichToSelectiveSleep.get(pendingState)
- && !mDeviceStatesOnWhichToSelectiveSleep.get(currentState)
- && isInteractive
- && isBootCompleted
- && !mFoldSettingProvider.shouldStayAwakeOnFold();
+ boolean shouldDeviceBePutToSleep(DeviceState pendingState, DeviceState currentState,
+ boolean isInteractive, boolean isBootCompleted) {
+ if (mDeviceStateManagerFlags.deviceStatePropertyMigration()) {
+ return pendingState.hasProperty(PROPERTY_POWER_CONFIGURATION_TRIGGER_SLEEP)
+ && !currentState.equals(INVALID_DEVICE_STATE)
+ && !currentState.hasProperty(PROPERTY_POWER_CONFIGURATION_TRIGGER_SLEEP)
+ && isInteractive
+ && isBootCompleted
+ && !mFoldSettingProvider.shouldStayAwakeOnFold();
+ } else {
+ return mDeviceStatesOnWhichToSelectiveSleep.get(pendingState.getIdentifier())
+ && !mDeviceStatesOnWhichToSelectiveSleep.get(currentState.getIdentifier())
+ && isInteractive
+ && isBootCompleted
+ && !mFoldSettingProvider.shouldStayAwakeOnFold();
+ }
}
private boolean areAllTransitioningDisplaysOffLocked() {
@@ -618,27 +642,25 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
}
private void transitionToPendingStateLocked() {
- resetLayoutLocked(mDeviceState, mPendingDeviceState, /* transitionValue= */ false);
+ resetLayoutLocked(mDeviceState.getIdentifier(),
+ mPendingDeviceState.getIdentifier(), /* transitionValue= */ false);
mDeviceState = mPendingDeviceState;
- mPendingDeviceState = DeviceStateManager.INVALID_DEVICE_STATE_IDENTIFIER;
+ mPendingDeviceState = INVALID_DEVICE_STATE;
applyLayoutLocked();
updateLogicalDisplaysLocked();
}
private void finishStateTransitionLocked(boolean force) {
- if (mPendingDeviceState == DeviceStateManager.INVALID_DEVICE_STATE_IDENTIFIER) {
+ if (mPendingDeviceState.equals(INVALID_DEVICE_STATE)) {
return;
}
- final boolean waitingToWakeDevice = mDeviceStatesOnWhichToWakeUp.get(mPendingDeviceState)
- && !mDeviceStatesOnWhichToWakeUp.get(mDeviceState)
- && !mInteractive && mBootCompleted;
+ final boolean waitingToWakeDevice = shouldDeviceBeWoken(mPendingDeviceState, mDeviceState,
+ mInteractive, mBootCompleted);
// The device should only wait for sleep if #shouldStayAwakeOnFold method returns false.
// If not, device should be marked ready for transition immediately.
- final boolean waitingToSleepDevice = mDeviceStatesOnWhichToSelectiveSleep.get(
- mPendingDeviceState)
- && !mDeviceStatesOnWhichToSelectiveSleep.get(mDeviceState)
- && mInteractive && mBootCompleted && !shouldStayAwakeOnFold();
+ final boolean waitingToSleepDevice = shouldDeviceBePutToSleep(mPendingDeviceState,
+ mDeviceState, mInteractive, mBootCompleted) && !shouldStayAwakeOnFold();
final boolean displaysOff = areAllTransitioningDisplaysOffLocked();
final boolean isReadyToTransition = displaysOff && !waitingToWakeDevice
@@ -1104,7 +1126,7 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
*/
private void applyLayoutLocked() {
final Layout oldLayout = mCurrentLayout;
- mCurrentLayout = mDeviceStateToLayoutMap.get(mDeviceState);
+ mCurrentLayout = mDeviceStateToLayoutMap.get(mDeviceState.getIdentifier());
Slog.i(TAG, "Applying layout: " + mCurrentLayout + ", Previous layout: " + oldLayout);
// Go through each of the displays in the current layout set.
@@ -1120,7 +1142,7 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
final DisplayDevice device = mDisplayDeviceRepo.getByAddressLocked(address);
if (device == null) {
Slog.w(TAG, "applyLayoutLocked: The display device (" + address + "), is not "
- + "available for the display state " + mDeviceState);
+ + "available for the display state " + mDeviceState.getIdentifier());
continue;
}
diff --git a/services/core/java/com/android/server/display/brightness/BrightnessUtils.java b/services/core/java/com/android/server/display/brightness/BrightnessUtils.java
index 8bf675cb33b1..d009e614d5b5 100644
--- a/services/core/java/com/android/server/display/brightness/BrightnessUtils.java
+++ b/services/core/java/com/android/server/display/brightness/BrightnessUtils.java
@@ -52,9 +52,8 @@ public final class BrightnessUtils {
* A utility to construct the DisplayBrightnessState
*/
public static DisplayBrightnessState constructDisplayBrightnessState(
- int brightnessChangeReason, float brightness, float sdrBrightness,
- String displayBrightnessStrategyName) {
- return constructDisplayBrightnessState(brightnessChangeReason, brightness, sdrBrightness,
+ int brightnessChangeReason, float brightness, String displayBrightnessStrategyName) {
+ return constructDisplayBrightnessState(brightnessChangeReason, brightness,
displayBrightnessStrategyName, /* slowChange= */ false);
}
@@ -62,13 +61,12 @@ public final class BrightnessUtils {
* A utility to construct the DisplayBrightnessState
*/
public static DisplayBrightnessState constructDisplayBrightnessState(
- int brightnessChangeReason, float brightness, float sdrBrightness,
+ int brightnessChangeReason, float brightness,
String displayBrightnessStrategyName, boolean slowChange) {
BrightnessReason brightnessReason = new BrightnessReason();
brightnessReason.setReason(brightnessChangeReason);
return new DisplayBrightnessState.Builder()
.setBrightness(brightness)
- .setSdrBrightness(sdrBrightness)
.setBrightnessReason(brightnessReason)
.setDisplayBrightnessStrategyName(displayBrightnessStrategyName)
.setIsSlowChange(slowChange)
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 220640270e02..88d2c007cf37 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
@@ -304,6 +304,9 @@ public class BrightnessClamperController {
modifiers.add(new BrightnessLowLuxModifier(handler, listener, context,
displayDeviceConfig));
}
+ if (flags.useNewHdrBrightnessModifier()) {
+ modifiers.add(new HdrBrightnessModifier());
+ }
return modifiers;
}
diff --git a/services/core/java/com/android/server/display/brightness/clamper/HdrBrightnessModifier.java b/services/core/java/com/android/server/display/brightness/clamper/HdrBrightnessModifier.java
new file mode 100644
index 000000000000..a829866ae6fc
--- /dev/null
+++ b/services/core/java/com/android/server/display/brightness/clamper/HdrBrightnessModifier.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.brightness.clamper;
+
+import android.hardware.display.DisplayManagerInternal;
+
+import com.android.server.display.DisplayBrightnessState;
+
+import java.io.PrintWriter;
+
+public class HdrBrightnessModifier implements BrightnessStateModifier {
+ @Override
+ public void apply(DisplayManagerInternal.DisplayPowerRequest request,
+ DisplayBrightnessState.Builder stateBuilder) {
+ // noop
+ }
+
+ @Override
+ public void dump(PrintWriter printWriter) {
+ // noop
+ }
+
+ @Override
+ public void stop() {
+ // noop
+ }
+
+ @Override
+ public boolean shouldListenToLightSensor() {
+ return false;
+ }
+
+ @Override
+ public void setAmbientLux(float lux) {
+ // noop
+ }
+}
diff --git a/services/core/java/com/android/server/display/brightness/clamper/HdrClamper.java b/services/core/java/com/android/server/display/brightness/clamper/HdrClamper.java
index 902daa4b7ce2..5c2db35717c5 100644
--- a/services/core/java/com/android/server/display/brightness/clamper/HdrClamper.java
+++ b/services/core/java/com/android/server/display/brightness/clamper/HdrClamper.java
@@ -133,7 +133,7 @@ public class HdrClamper {
// new token not null and hdr min % of the screen is set, subscribe.
// e.g. for virtual display, HBM data will be missing and HdrListener
// should not be registered
- if (displayToken != null && mHdrListener.mHdrMinPixels >= 0) {
+ if (displayToken != null && mHdrListener.mHdrMinPixels >= 0 && hasBrightnessLimits()) {
mHdrListener.register(displayToken);
mRegisteredDisplayToken = displayToken;
}
@@ -179,6 +179,10 @@ public class HdrClamper {
pw.println(" mAutoBrightnessEnabled=" + mAutoBrightnessEnabled);
}
+ private boolean hasBrightnessLimits() {
+ return mHdrBrightnessData != null && !mHdrBrightnessData.maxBrightnessLimits.isEmpty();
+ }
+
private void reset() {
if (mMaxBrightness == PowerManager.BRIGHTNESS_MAX
&& mDesiredMaxBrightness == PowerManager.BRIGHTNESS_MAX && mTransitionRate == -1f
@@ -214,11 +218,11 @@ public class HdrClamper {
mDesiredMaxBrightness = expectedMaxBrightness;
long debounceTime;
if (mDesiredMaxBrightness > mMaxBrightness) {
- debounceTime = mHdrBrightnessData.mBrightnessIncreaseDebounceMillis;
- mDesiredTransitionRate = mHdrBrightnessData.mScreenBrightnessRampIncrease;
+ debounceTime = mHdrBrightnessData.brightnessIncreaseDebounceMillis;
+ mDesiredTransitionRate = mHdrBrightnessData.screenBrightnessRampIncrease;
} else {
- debounceTime = mHdrBrightnessData.mBrightnessDecreaseDebounceMillis;
- mDesiredTransitionRate = mHdrBrightnessData.mScreenBrightnessRampDecrease;
+ debounceTime = mHdrBrightnessData.brightnessDecreaseDebounceMillis;
+ mDesiredTransitionRate = mHdrBrightnessData.screenBrightnessRampDecrease;
}
mHandler.removeCallbacks(mDebouncer);
@@ -232,7 +236,7 @@ public class HdrClamper {
float foundAmbientBoundary = Float.MAX_VALUE;
float foundMaxBrightness = PowerManager.BRIGHTNESS_MAX;
for (Map.Entry<Float, Float> brightnessPoint :
- data.mMaxBrightnessLimits.entrySet()) {
+ data.maxBrightnessLimits.entrySet()) {
float ambientBoundary = brightnessPoint.getKey();
// find ambient lux upper boundary closest to current ambient lux
if (ambientBoundary > ambientLux && ambientBoundary < foundAmbientBoundary) {
diff --git a/services/core/java/com/android/server/display/brightness/strategy/AutoBrightnessFallbackStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/AutoBrightnessFallbackStrategy.java
index 16bf177f191b..d8b95ec3b5c9 100644
--- a/services/core/java/com/android/server/display/brightness/strategy/AutoBrightnessFallbackStrategy.java
+++ b/services/core/java/com/android/server/display/brightness/strategy/AutoBrightnessFallbackStrategy.java
@@ -75,7 +75,6 @@ public final class AutoBrightnessFallbackStrategy implements DisplayBrightnessSt
brightnessReason.setReason(BrightnessReason.REASON_SCREEN_OFF_BRIGHTNESS_SENSOR);
return new DisplayBrightnessState.Builder()
.setBrightness(brightness)
- .setSdrBrightness(brightness)
.setBrightnessReason(brightnessReason)
.setDisplayBrightnessStrategyName(getName())
.setShouldUpdateScreenBrightnessSetting(brightness
diff --git a/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java
index ddb091dd170d..706b4a63f31b 100644
--- a/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java
+++ b/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java
@@ -297,7 +297,6 @@ public class AutomaticBrightnessStrategy extends AutomaticBrightnessStrategy2
/* isAutomaticBrightnessAdjusted = */ true);
return new DisplayBrightnessState.Builder()
.setBrightness(brightness)
- .setSdrBrightness(brightness)
.setBrightnessReason(brightnessReason)
.setDisplayBrightnessStrategyName(getName())
.setIsSlowChange(mIsSlowChange)
diff --git a/services/core/java/com/android/server/display/brightness/strategy/BoostBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/BoostBrightnessStrategy.java
index 009a47ad8ade..2ef7ea925fdf 100644
--- a/services/core/java/com/android/server/display/brightness/strategy/BoostBrightnessStrategy.java
+++ b/services/core/java/com/android/server/display/brightness/strategy/BoostBrightnessStrategy.java
@@ -42,7 +42,6 @@ public class BoostBrightnessStrategy implements DisplayBrightnessStrategy {
// the brightness
DisplayBrightnessState displayBrightnessState =
BrightnessUtils.constructDisplayBrightnessState(BrightnessReason.REASON_BOOST,
- PowerManager.BRIGHTNESS_MAX,
PowerManager.BRIGHTNESS_MAX, getName());
return displayBrightnessState;
}
diff --git a/services/core/java/com/android/server/display/brightness/strategy/DozeBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/DozeBrightnessStrategy.java
index 2b493f3a181f..0855c9e098c4 100644
--- a/services/core/java/com/android/server/display/brightness/strategy/DozeBrightnessStrategy.java
+++ b/services/core/java/com/android/server/display/brightness/strategy/DozeBrightnessStrategy.java
@@ -36,7 +36,6 @@ public class DozeBrightnessStrategy implements DisplayBrightnessStrategy {
// the brightness
return BrightnessUtils.constructDisplayBrightnessState(BrightnessReason.REASON_DOZE,
strategyExecutionRequest.getDisplayPowerRequest().dozeScreenBrightness,
- strategyExecutionRequest.getDisplayPowerRequest().dozeScreenBrightness,
getName());
}
diff --git a/services/core/java/com/android/server/display/brightness/strategy/FallbackBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/FallbackBrightnessStrategy.java
index 0b92317a61cb..7c0c9312888e 100644
--- a/services/core/java/com/android/server/display/brightness/strategy/FallbackBrightnessStrategy.java
+++ b/services/core/java/com/android/server/display/brightness/strategy/FallbackBrightnessStrategy.java
@@ -39,7 +39,6 @@ public class FallbackBrightnessStrategy implements DisplayBrightnessStrategy{
brightnessReason.setReason(BrightnessReason.REASON_MANUAL);
return new DisplayBrightnessState.Builder()
.setBrightness(strategyExecutionRequest.getCurrentScreenBrightness())
- .setSdrBrightness(strategyExecutionRequest.getCurrentScreenBrightness())
.setBrightnessReason(brightnessReason)
.setDisplayBrightnessStrategyName(getName())
// The fallback brightness might change due to clamping. Make sure we tell the rest
diff --git a/services/core/java/com/android/server/display/brightness/strategy/FollowerBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/FollowerBrightnessStrategy.java
index 5a07ce2a719d..7ab92d101fc6 100644
--- a/services/core/java/com/android/server/display/brightness/strategy/FollowerBrightnessStrategy.java
+++ b/services/core/java/com/android/server/display/brightness/strategy/FollowerBrightnessStrategy.java
@@ -53,7 +53,7 @@ public class FollowerBrightnessStrategy implements DisplayBrightnessStrategy {
// Todo(b/241308599): Introduce a validator class and add validations before setting
// the brightness
return BrightnessUtils.constructDisplayBrightnessState(BrightnessReason.REASON_FOLLOWER,
- mBrightnessToFollow, mBrightnessToFollow, getName(), mBrightnessToFollowSlowChange);
+ mBrightnessToFollow, getName(), mBrightnessToFollowSlowChange);
}
@Override
diff --git a/services/core/java/com/android/server/display/brightness/strategy/InvalidBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/InvalidBrightnessStrategy.java
index 9dc6cffe5c1e..f9e56bbe47d1 100644
--- a/services/core/java/com/android/server/display/brightness/strategy/InvalidBrightnessStrategy.java
+++ b/services/core/java/com/android/server/display/brightness/strategy/InvalidBrightnessStrategy.java
@@ -34,8 +34,7 @@ public class InvalidBrightnessStrategy implements DisplayBrightnessStrategy {
public DisplayBrightnessState updateBrightness(
StrategyExecutionRequest strategyExecutionRequest) {
return BrightnessUtils.constructDisplayBrightnessState(BrightnessReason.REASON_UNKNOWN,
- PowerManager.BRIGHTNESS_INVALID_FLOAT, PowerManager.BRIGHTNESS_INVALID_FLOAT,
- getName());
+ PowerManager.BRIGHTNESS_INVALID_FLOAT, getName());
}
@Override
diff --git a/services/core/java/com/android/server/display/brightness/strategy/OffloadBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/OffloadBrightnessStrategy.java
index b46873aec814..1d7d3a6fa3ef 100644
--- a/services/core/java/com/android/server/display/brightness/strategy/OffloadBrightnessStrategy.java
+++ b/services/core/java/com/android/server/display/brightness/strategy/OffloadBrightnessStrategy.java
@@ -55,7 +55,6 @@ public class OffloadBrightnessStrategy implements DisplayBrightnessStrategy {
brightnessReason.setReason(BrightnessReason.REASON_OFFLOAD);
return new DisplayBrightnessState.Builder()
.setBrightness(offloadBrightness)
- .setSdrBrightness(offloadBrightness)
.setBrightnessReason(brightnessReason)
.setDisplayBrightnessStrategyName(getName())
.setIsSlowChange(false)
diff --git a/services/core/java/com/android/server/display/brightness/strategy/OverrideBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/OverrideBrightnessStrategy.java
index a2982b16454f..40a495c85467 100644
--- a/services/core/java/com/android/server/display/brightness/strategy/OverrideBrightnessStrategy.java
+++ b/services/core/java/com/android/server/display/brightness/strategy/OverrideBrightnessStrategy.java
@@ -35,8 +35,7 @@ public class OverrideBrightnessStrategy implements DisplayBrightnessStrategy {
// the brightness
return BrightnessUtils.constructDisplayBrightnessState(BrightnessReason.REASON_OVERRIDE,
strategyExecutionRequest.getDisplayPowerRequest().screenBrightnessOverride,
- strategyExecutionRequest.getDisplayPowerRequest()
- .screenBrightnessOverride, getName());
+ getName());
}
@Override
diff --git a/services/core/java/com/android/server/display/brightness/strategy/ScreenOffBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/ScreenOffBrightnessStrategy.java
index 6a3162c75dc5..fe7a6b754cbc 100644
--- a/services/core/java/com/android/server/display/brightness/strategy/ScreenOffBrightnessStrategy.java
+++ b/services/core/java/com/android/server/display/brightness/strategy/ScreenOffBrightnessStrategy.java
@@ -36,7 +36,6 @@ public class ScreenOffBrightnessStrategy implements DisplayBrightnessStrategy {
// Todo(b/241308599): Introduce a validator class and add validations before setting
// the brightness
return BrightnessUtils.constructDisplayBrightnessState(BrightnessReason.REASON_SCREEN_OFF,
- PowerManager.BRIGHTNESS_OFF_FLOAT,
PowerManager.BRIGHTNESS_OFF_FLOAT, getName());
}
diff --git a/services/core/java/com/android/server/display/brightness/strategy/TemporaryBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/TemporaryBrightnessStrategy.java
index 6b8817a3b62a..ca0beefd86fd 100644
--- a/services/core/java/com/android/server/display/brightness/strategy/TemporaryBrightnessStrategy.java
+++ b/services/core/java/com/android/server/display/brightness/strategy/TemporaryBrightnessStrategy.java
@@ -48,7 +48,6 @@ public class TemporaryBrightnessStrategy implements DisplayBrightnessStrategy {
// the brightness
DisplayBrightnessState displayBrightnessState =
BrightnessUtils.constructDisplayBrightnessState(BrightnessReason.REASON_TEMPORARY,
- mTemporaryScreenBrightness,
mTemporaryScreenBrightness, getName());
return displayBrightnessState;
}
diff --git a/services/core/java/com/android/server/display/config/DisplayDeviceConfigUtils.java b/services/core/java/com/android/server/display/config/DisplayDeviceConfigUtils.java
new file mode 100644
index 000000000000..5b4e8d51a168
--- /dev/null
+++ b/services/core/java/com/android/server/display/config/DisplayDeviceConfigUtils.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.config;
+
+import android.annotation.Nullable;
+import android.util.Slog;
+import android.util.Spline;
+
+import java.math.BigDecimal;
+import java.util.List;
+import java.util.function.Function;
+
+public class DisplayDeviceConfigUtils {
+ private static final String TAG = "DisplayDeviceConfigUtils";
+
+ /**
+ * Create Spline from generic data
+ * @param points - points for Spline in format (x0, y0), (x1, y1) etc
+ * @param xExtractor - extract X component from generic data
+ * @param yExtractor - extract Y component from generic data
+ */
+ @Nullable
+ public static <T> Spline createSpline(List<T> points, Function<T, BigDecimal> xExtractor,
+ Function<T, BigDecimal> yExtractor) {
+ int size = points.size();
+ if (size == 0) {
+ return null;
+ }
+
+ float[] x = new float[size];
+ float[] y = new float[size];
+
+ int i = 0;
+ for (T point : points) {
+ x[i] = xExtractor.apply(point).floatValue();
+ if (i > 0) {
+ if (x[i] <= x[i - 1]) {
+ Slog.e(TAG, "spline control points must be strictly increasing, ignoring "
+ + "configuration. x: " + x[i] + " <= " + x[i - 1]);
+ return null;
+ }
+ }
+ y[i] = yExtractor.apply(point).floatValue();
+ ++i;
+ }
+
+ return Spline.createSpline(x, y);
+ }
+}
diff --git a/services/core/java/com/android/server/display/config/HdrBrightnessData.java b/services/core/java/com/android/server/display/config/HdrBrightnessData.java
index 837fbf7ca17c..c9408077e5af 100644
--- a/services/core/java/com/android/server/display/config/HdrBrightnessData.java
+++ b/services/core/java/com/android/server/display/config/HdrBrightnessData.java
@@ -16,63 +16,138 @@
package com.android.server.display.config;
+import static com.android.server.display.config.HighBrightnessModeData.HDR_PERCENT_OF_SCREEN_REQUIRED_DEFAULT;
+
import android.annotation.Nullable;
+import android.util.Spline;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.display.DisplayBrightnessState;
+import java.math.BigDecimal;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Brightness config for HDR content
+ * <pre>
+ * {@code
+ * <displayConfiguration>
+ * ...
+ * <hdrBrightnessConfig>
+ * <brightnessMap>
+ * <point>
+ * <first>500</first>
+ * <second>0.3</second>
+ * </point>
+ * <point>
+ * <first>1200</first>
+ * <second>0.6</second>
+ * </point>
+ * </brightnessMap>
+ * <brightnessIncreaseDebounceMillis>1000</brightnessIncreaseDebounceMillis>
+ * <brightnessIncreaseDurationMillis>10000</brightnessIncreaseDurationMillis>
+ * <brightnessDecreaseDebounceMillis>13000</brightnessDecreaseDebounceMillis>
+ * <brightnessDecreaseDurationMillis>10000</brightnessDecreaseDurationMillis>
+ * <minimumHdrPercentOfScreenForNbm>0.2</minimumHdrPercentOfScreenForNbm>
+ * <minimumHdrPercentOfScreenForHbm>0.5</minimumHdrPercentOfScreenForHbm>
+ * <allowInLowPowerMode>true</allowInLowPowerMode>
+ * <sdrHdrRatioMap>
+ * <point>
+ * <first>2.0</first>
+ * <second>4.0</second>
+ * </point>
+ * <point>
+ * <first>100</first>
+ * <second>8.0</second>
+ * </point>
+ * </sdrHdrRatioMap>
+ * </hdrBrightnessConfig>
+ * ...
+ * </displayConfiguration>
+ * }
+ * </pre>
*/
public class HdrBrightnessData {
+ private static final String TAG = "HdrBrightnessData";
/**
* Lux to brightness map
*/
- public final Map<Float, Float> mMaxBrightnessLimits;
+ public final Map<Float, Float> maxBrightnessLimits;
/**
* Debounce time for brightness increase
*/
- public final long mBrightnessIncreaseDebounceMillis;
+ public final long brightnessIncreaseDebounceMillis;
/**
* Brightness increase animation speed
*/
- public final float mScreenBrightnessRampIncrease;
+ public final float screenBrightnessRampIncrease;
/**
* Debounce time for brightness decrease
*/
- public final long mBrightnessDecreaseDebounceMillis;
+ public final long brightnessDecreaseDebounceMillis;
/**
* Brightness decrease animation speed
*/
- public final float mScreenBrightnessRampDecrease;
+ public final float screenBrightnessRampDecrease;
+
+ /**
+ * Min Hdr layer size to start hdr brightness boost up to high brightness mode transition point
+ */
+ public final float minimumHdrPercentOfScreenForNbm;
+
+ /**
+ * Min Hdr layer size to start hdr brightness boost above high brightness mode transition point
+ */
+ public final float minimumHdrPercentOfScreenForHbm;
+
+ /**
+ * If Hdr brightness boost allowed in low power mode
+ */
+ public final boolean allowInLowPowerMode;
+
+ /**
+ * brightness to boost ratio spline
+ */
+ @Nullable
+ public final Spline sdrToHdrRatioSpline;
@VisibleForTesting
public HdrBrightnessData(Map<Float, Float> maxBrightnessLimits,
long brightnessIncreaseDebounceMillis, float screenBrightnessRampIncrease,
- long brightnessDecreaseDebounceMillis, float screenBrightnessRampDecrease) {
- mMaxBrightnessLimits = maxBrightnessLimits;
- mBrightnessIncreaseDebounceMillis = brightnessIncreaseDebounceMillis;
- mScreenBrightnessRampIncrease = screenBrightnessRampIncrease;
- mBrightnessDecreaseDebounceMillis = brightnessDecreaseDebounceMillis;
- mScreenBrightnessRampDecrease = screenBrightnessRampDecrease;
+ long brightnessDecreaseDebounceMillis, float screenBrightnessRampDecrease,
+ float minimumHdrPercentOfScreenForNbm, float minimumHdrPercentOfScreenForHbm,
+ boolean allowInLowPowerMode, @Nullable Spline sdrToHdrRatioSpline) {
+ this.maxBrightnessLimits = maxBrightnessLimits;
+ this.brightnessIncreaseDebounceMillis = brightnessIncreaseDebounceMillis;
+ this.screenBrightnessRampIncrease = screenBrightnessRampIncrease;
+ this.brightnessDecreaseDebounceMillis = brightnessDecreaseDebounceMillis;
+ this.screenBrightnessRampDecrease = screenBrightnessRampDecrease;
+ this.minimumHdrPercentOfScreenForNbm = minimumHdrPercentOfScreenForNbm;
+ this.minimumHdrPercentOfScreenForHbm = minimumHdrPercentOfScreenForHbm;
+ this.allowInLowPowerMode = allowInLowPowerMode;
+ this.sdrToHdrRatioSpline = sdrToHdrRatioSpline;
}
@Override
public String toString() {
return "HdrBrightnessData {"
- + "mMaxBrightnessLimits: " + mMaxBrightnessLimits
- + ", mBrightnessIncreaseDebounceMillis: " + mBrightnessIncreaseDebounceMillis
- + ", mScreenBrightnessRampIncrease: " + mScreenBrightnessRampIncrease
- + ", mBrightnessDecreaseDebounceMillis: " + mBrightnessDecreaseDebounceMillis
- + ", mScreenBrightnessRampDecrease: " + mScreenBrightnessRampDecrease
+ + "mMaxBrightnessLimits: " + maxBrightnessLimits
+ + ", mBrightnessIncreaseDebounceMillis: " + brightnessIncreaseDebounceMillis
+ + ", mScreenBrightnessRampIncrease: " + screenBrightnessRampIncrease
+ + ", mBrightnessDecreaseDebounceMillis: " + brightnessDecreaseDebounceMillis
+ + ", mScreenBrightnessRampDecrease: " + screenBrightnessRampDecrease
+ + ", minimumHdrPercentOfScreenForNbm: " + minimumHdrPercentOfScreenForNbm
+ + ", minimumHdrPercentOfScreenForHbm: " + minimumHdrPercentOfScreenForHbm
+ + ", allowInLowPowerMode: " + allowInLowPowerMode
+ + ", sdrToHdrRatioSpline: " + sdrToHdrRatioSpline
+ "} ";
}
@@ -83,7 +158,7 @@ public class HdrBrightnessData {
public static HdrBrightnessData loadConfig(DisplayConfiguration config) {
HdrBrightnessConfig hdrConfig = config.getHdrBrightnessConfig();
if (hdrConfig == null) {
- return null;
+ return getFallbackData(config.getHighBrightnessMode());
}
List<NonNegativeFloatToFloatPoint> points = hdrConfig.getBrightnessMap().getPoint();
@@ -92,10 +167,59 @@ public class HdrBrightnessData {
brightnessLimits.put(point.getFirst().floatValue(), point.getSecond().floatValue());
}
+ float minHdrPercentForHbm = hdrConfig.getMinimumHdrPercentOfScreenForHbm() != null
+ ? hdrConfig.getMinimumHdrPercentOfScreenForHbm().floatValue()
+ : getFallbackHdrPercent(config.getHighBrightnessMode());
+
+ float minHdrPercentForNbm = hdrConfig.getMinimumHdrPercentOfScreenForNbm() != null
+ ? hdrConfig.getMinimumHdrPercentOfScreenForNbm().floatValue() : minHdrPercentForHbm;
+
return new HdrBrightnessData(brightnessLimits,
hdrConfig.getBrightnessIncreaseDebounceMillis().longValue(),
hdrConfig.getScreenBrightnessRampIncrease().floatValue(),
hdrConfig.getBrightnessDecreaseDebounceMillis().longValue(),
- hdrConfig.getScreenBrightnessRampDecrease().floatValue());
+ hdrConfig.getScreenBrightnessRampDecrease().floatValue(),
+ minHdrPercentForNbm, minHdrPercentForHbm, hdrConfig.getAllowInLowPowerMode(),
+ getSdrHdrRatioSpline(hdrConfig, config.getHighBrightnessMode()));
+ }
+
+ @Nullable
+ private static HdrBrightnessData getFallbackData(HighBrightnessMode hbm) {
+ if (hbm == null) {
+ return null;
+ }
+ float fallbackPercent = getFallbackHdrPercent(hbm);
+ Spline fallbackSpline = getFallbackSdrHdrRatioSpline(hbm);
+ return new HdrBrightnessData(Collections.emptyMap(),
+ 0, DisplayBrightnessState.CUSTOM_ANIMATION_RATE_NOT_SET,
+ 0, DisplayBrightnessState.CUSTOM_ANIMATION_RATE_NOT_SET,
+ fallbackPercent, fallbackPercent, false, fallbackSpline);
+ }
+
+ private static float getFallbackHdrPercent(HighBrightnessMode hbm) {
+ BigDecimal minHdrPctOfScreen = hbm != null ? hbm.getMinimumHdrPercentOfScreen_all() : null;
+ return minHdrPctOfScreen != null ? minHdrPctOfScreen.floatValue()
+ : HDR_PERCENT_OF_SCREEN_REQUIRED_DEFAULT;
+ }
+
+ @Nullable
+ private static Spline getSdrHdrRatioSpline(HdrBrightnessConfig hdrConfig,
+ HighBrightnessMode hbm) {
+ NonNegativeFloatToFloatMap sdrHdrRatioMap = hdrConfig.getSdrHdrRatioMap();
+ if (sdrHdrRatioMap == null) {
+ return getFallbackSdrHdrRatioSpline(hbm);
+ }
+ return DisplayDeviceConfigUtils.createSpline(sdrHdrRatioMap.getPoint(),
+ NonNegativeFloatToFloatPoint::getFirst, NonNegativeFloatToFloatPoint::getSecond);
+ }
+
+ @Nullable
+ private static Spline getFallbackSdrHdrRatioSpline(HighBrightnessMode hbm) {
+ SdrHdrRatioMap fallbackMap = hbm != null ? hbm.getSdrHdrRatioMap_all() : null;
+ if (fallbackMap == null) {
+ return null;
+ }
+ return DisplayDeviceConfigUtils.createSpline(fallbackMap.getPoint(),
+ SdrHdrRatioPoint::getSdrNits, SdrHdrRatioPoint::getHdrRatio);
}
}
diff --git a/services/core/java/com/android/server/display/config/HighBrightnessModeData.java b/services/core/java/com/android/server/display/config/HighBrightnessModeData.java
new file mode 100644
index 000000000000..dc2f976748e6
--- /dev/null
+++ b/services/core/java/com/android/server/display/config/HighBrightnessModeData.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.config;
+
+import android.annotation.Nullable;
+import android.util.Slog;
+import android.util.Spline;
+import android.view.SurfaceControl;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.math.BigDecimal;
+import java.util.function.Function;
+
+/**
+ * Container for high brightness mode configuration data.
+ */
+public class HighBrightnessModeData {
+ private static final String TAG = "HighBrightnessModeData";
+
+ static final float HDR_PERCENT_OF_SCREEN_REQUIRED_DEFAULT = 0.5f;
+
+ /** Minimum lux needed to enter high brightness mode */
+ public final float minimumLux;
+
+ /** Brightness level at which we transition from normal to high-brightness. */
+ public final float transitionPoint;
+
+ /** Whether HBM is allowed when {@code Settings.Global.LOW_POWER_MODE} is active. */
+ public final boolean allowInLowPowerMode;
+
+ /** Time window for HBM. */
+ public final long timeWindowMillis;
+
+ /** Maximum time HBM is allowed to be during in a {@code timeWindowMillis}. */
+ public final long timeMaxMillis;
+
+ /** Minimum time that HBM can be on before being enabled. */
+ public final long timeMinMillis;
+
+ /** Minimum HDR video size to enter high brightness mode */
+ public final float minimumHdrPercentOfScreen;
+
+ @Nullable
+ public final Spline sdrToHdrRatioSpline;
+
+ @Nullable
+ public final SurfaceControl.RefreshRateRange refreshRateLimit;
+
+ public final boolean isHighBrightnessModeEnabled;
+
+ @VisibleForTesting
+ public HighBrightnessModeData(float minimumLux, float transitionPoint, long timeWindowMillis,
+ long timeMaxMillis, long timeMinMillis, boolean allowInLowPowerMode,
+ float minimumHdrPercentOfScreen, @Nullable Spline sdrToHdrRatioSpline,
+ @Nullable SurfaceControl.RefreshRateRange refreshRateLimit,
+ boolean isHighBrightnessModeEnabled) {
+ this.minimumLux = minimumLux;
+ this.transitionPoint = transitionPoint;
+ this.timeWindowMillis = timeWindowMillis;
+ this.timeMaxMillis = timeMaxMillis;
+ this.timeMinMillis = timeMinMillis;
+ this.allowInLowPowerMode = allowInLowPowerMode;
+ this.minimumHdrPercentOfScreen = minimumHdrPercentOfScreen;
+ this.sdrToHdrRatioSpline = sdrToHdrRatioSpline;
+ this.refreshRateLimit = refreshRateLimit;
+ this.isHighBrightnessModeEnabled = isHighBrightnessModeEnabled;
+ }
+
+ @Override
+ public String toString() {
+ return "HBM{"
+ + "minLux: " + minimumLux
+ + ", transition: " + transitionPoint
+ + ", timeWindow: " + timeWindowMillis + "ms"
+ + ", timeMax: " + timeMaxMillis + "ms"
+ + ", timeMin: " + timeMinMillis + "ms"
+ + ", allowInLowPowerMode: " + allowInLowPowerMode
+ + ", minimumHdrPercentOfScreen: " + minimumHdrPercentOfScreen
+ + ", mSdrToHdrRatioSpline=" + sdrToHdrRatioSpline
+ + ", refreshRateLimit=" + refreshRateLimit
+ + ", isHighBrightnessModeEnabled=" + isHighBrightnessModeEnabled
+ + "} ";
+ }
+
+ /**
+ * Loads HighBrightnessModeData from DisplayConfiguration
+ */
+ public static HighBrightnessModeData loadHighBrightnessModeData(DisplayConfiguration config,
+ Function<HighBrightnessMode, Float> transitionPointProvider) {
+ final HighBrightnessMode hbm = config.getHighBrightnessMode();
+ float minimumLux = 0f;
+ float transitionPoint = 0f;
+ long timeWindowMillis = 0L;
+ long timeMaxMillis = 0L;
+ long timeMinMillis = 0L;
+ boolean allowInLowPowerMode = false;
+ float minimumHdrPercentOfScreen = HDR_PERCENT_OF_SCREEN_REQUIRED_DEFAULT;
+ Spline sdrToHdrRatioSpline = null;
+ SurfaceControl.RefreshRateRange refreshRateLimit = null;
+ boolean isEnabled = false;
+
+ if (hbm != null) {
+ minimumLux = hbm.getMinimumLux_all().floatValue();
+ transitionPoint = transitionPointProvider.apply(hbm);
+ HbmTiming hbmTiming = hbm.getTiming_all();
+ timeWindowMillis = hbmTiming.getTimeWindowSecs_all().longValue() * 1000;
+ timeMaxMillis = hbmTiming.getTimeMaxSecs_all().longValue() * 1000;
+ timeMinMillis = hbmTiming.getTimeMinSecs_all().longValue() * 1000;
+ allowInLowPowerMode = hbm.getAllowInLowPowerMode_all();
+ BigDecimal minHdrPctOfScreen = hbm.getMinimumHdrPercentOfScreen_all();
+ if (minHdrPctOfScreen != null) {
+ minimumHdrPercentOfScreen = minHdrPctOfScreen.floatValue();
+ if (minimumHdrPercentOfScreen > 1 || minimumHdrPercentOfScreen < 0) {
+ Slog.w(TAG, "Invalid minimum HDR percent of screen: "
+ + minimumHdrPercentOfScreen);
+ minimumHdrPercentOfScreen = HDR_PERCENT_OF_SCREEN_REQUIRED_DEFAULT;
+ }
+ }
+
+ sdrToHdrRatioSpline = loadSdrHdrRatioMap(hbm);
+ RefreshRateRange rr = hbm.getRefreshRate_all();
+ if (rr != null) {
+ refreshRateLimit = new SurfaceControl.RefreshRateRange(
+ rr.getMinimum().floatValue(), rr.getMaximum().floatValue());
+ }
+ isEnabled = hbm.getEnabled();
+ }
+ return new HighBrightnessModeData(minimumLux, transitionPoint,
+ timeWindowMillis, timeMaxMillis, timeMinMillis, allowInLowPowerMode,
+ minimumHdrPercentOfScreen, sdrToHdrRatioSpline, refreshRateLimit, isEnabled);
+
+ }
+
+ private static Spline loadSdrHdrRatioMap(HighBrightnessMode hbmConfig) {
+ final SdrHdrRatioMap sdrHdrRatioMap = hbmConfig.getSdrHdrRatioMap_all();
+ if (sdrHdrRatioMap == null) {
+ return null;
+ }
+ return DisplayDeviceConfigUtils.createSpline(sdrHdrRatioMap.getPoint(),
+ SdrHdrRatioPoint::getSdrNits, SdrHdrRatioPoint::getHdrRatio);
+ }
+}
diff --git a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
index 41d18cd6bf12..3ce7d2a676b0 100644
--- a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
+++ b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
@@ -184,6 +184,11 @@ public class DisplayManagerFlags {
Flags.FLAG_OFFLOAD_SESSION_CANCEL_BLOCK_SCREEN_ON,
Flags::offloadSessionCancelBlockScreenOn);
+ private final FlagState mNewHdrBrightnessModifier =
+ new FlagState(
+ Flags.FLAG_NEW_HDR_BRIGHTNESS_MODIFIER,
+ Flags::newHdrBrightnessModifier);
+
/**
* @return {@code true} if 'port' is allowed in display layout configuration file.
*/
@@ -373,6 +378,13 @@ public class DisplayManagerFlags {
}
/**
+ * @return Whether to use new HDR brightness modifier or not
+ */
+ public boolean useNewHdrBrightnessModifier() {
+ return mNewHdrBrightnessModifier.isEnabled();
+ }
+
+ /**
* dumps all flagstates
* @param pw printWriter
*/
@@ -409,6 +421,7 @@ public class DisplayManagerFlags {
pw.println(" " + mSynthetic60hzModes);
pw.println(" " + mOffloadDozeOverrideHoldsWakelock);
pw.println(" " + mOffloadSessionCancelBlockScreenOn);
+ pw.println(" " + mNewHdrBrightnessModifier);
}
private static class FlagState {
diff --git a/services/core/java/com/android/server/display/feature/display_flags.aconfig b/services/core/java/com/android/server/display/feature/display_flags.aconfig
index 1ea5c0b23be1..fd3af2383e1b 100644
--- a/services/core/java/com/android/server/display/feature/display_flags.aconfig
+++ b/services/core/java/com/android/server/display/feature/display_flags.aconfig
@@ -307,3 +307,11 @@ flag {
bug: "331725519"
is_fixed_read_only: true
}
+
+flag {
+ name: "new_hdr_brightness_modifier"
+ namespace: "display_manager"
+ description: "Flag for new HDR brightness clamper."
+ bug: "331275392"
+ is_fixed_read_only: true
+}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java b/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java
index 88da6fb94754..550f68fbc94c 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java
@@ -660,7 +660,11 @@ public class HdmiCecNetwork {
.setPortId(physicalAddressToPortId(physicalAddress))
.setDeviceType(type)
.build();
- updateCecDevice(updatedDeviceInfo);
+ if (deviceInfo.getPhysicalAddress() != physicalAddress) {
+ addCecDevice(updatedDeviceInfo);
+ } else {
+ updateCecDevice(updatedDeviceInfo);
+ }
}
}
diff --git a/services/core/java/com/android/server/inputmethod/AdditionalSubtypeMapRepository.java b/services/core/java/com/android/server/inputmethod/AdditionalSubtypeMapRepository.java
index 82ecb4acb197..996859027e91 100644
--- a/services/core/java/com/android/server/inputmethod/AdditionalSubtypeMapRepository.java
+++ b/services/core/java/com/android/server/inputmethod/AdditionalSubtypeMapRepository.java
@@ -18,20 +18,14 @@ package com.android.server.inputmethod;
import android.annotation.AnyThread;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.annotation.WorkerThread;
-import android.content.Context;
-import android.content.pm.UserInfo;
import android.os.Handler;
import android.os.Process;
import android.util.IntArray;
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.inputmethod.DirectBootAwareness;
-import com.android.server.LocalServices;
-import com.android.server.pm.UserManagerInternal;
import java.util.ArrayList;
import java.util.concurrent.locks.Condition;
@@ -225,49 +219,12 @@ final class AdditionalSubtypeMapRepository {
sWriter.startThread();
}
- static void initialize(@NonNull Handler handler, @NonNull Context context) {
- final UserManagerInternal userManagerInternal =
- LocalServices.getService(UserManagerInternal.class);
- handler.post(() -> {
- userManagerInternal.addUserLifecycleListener(
- new UserManagerInternal.UserLifecycleListener() {
- @Override
- public void onUserCreated(UserInfo user, @Nullable Object token) {
- final int userId = user.id;
- sWriter.onUserCreated(userId);
- handler.post(() -> {
- synchronized (ImfLock.class) {
- if (!sPerUserMap.contains(userId)) {
- final AdditionalSubtypeMap additionalSubtypeMap =
- AdditionalSubtypeUtils.load(userId);
- sPerUserMap.put(userId, additionalSubtypeMap);
- final InputMethodSettings settings =
- InputMethodManagerService
- .queryInputMethodServicesInternal(context,
- userId,
- additionalSubtypeMap,
- DirectBootAwareness.AUTO);
- InputMethodSettingsRepository.put(userId, settings);
- }
- }
- });
- }
-
- @Override
- public void onUserRemoved(UserInfo user) {
- final int userId = user.id;
- sWriter.onUserRemoved(userId);
- handler.post(() -> {
- synchronized (ImfLock.class) {
- sPerUserMap.remove(userId);
- }
- });
- }
- });
+ @AnyThread
+ static void remove(@UserIdInt int userId, @NonNull Handler ioHandler) {
+ sWriter.onUserRemoved(userId);
+ ioHandler.post(() -> {
synchronized (ImfLock.class) {
- for (int userId : userManagerInternal.getUserIds()) {
- sPerUserMap.put(userId, AdditionalSubtypeUtils.load(userId));
- }
+ sPerUserMap.remove(userId);
}
});
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 0dbaaf398e00..e1803dc7caf6 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -26,6 +26,7 @@ import static android.provider.Settings.Secure.STYLUS_HANDWRITING_DEFAULT_VALUE;
import static android.provider.Settings.Secure.STYLUS_HANDWRITING_ENABLED;
import static android.server.inputmethod.InputMethodManagerServiceProto.BACK_DISPOSITION;
import static android.server.inputmethod.InputMethodManagerServiceProto.BOUND_TO_METHOD;
+import static android.server.inputmethod.InputMethodManagerServiceProto.CONCURRENT_MULTI_USER_MODE_ENABLED;
import static android.server.inputmethod.InputMethodManagerServiceProto.CUR_ATTRIBUTE;
import static android.server.inputmethod.InputMethodManagerServiceProto.CUR_CLIENT;
import static android.server.inputmethod.InputMethodManagerServiceProto.CUR_FOCUSED_WINDOW_SOFT_INPUT_MODE;
@@ -78,6 +79,7 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
+import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.hardware.input.InputManager;
import android.inputmethodservice.InputMethodService;
@@ -88,6 +90,7 @@ import android.os.Debug;
import android.os.Handler;
import android.os.IBinder;
import android.os.LocaleList;
+import android.os.Looper;
import android.os.Message;
import android.os.Process;
import android.os.RemoteException;
@@ -334,6 +337,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
final Resources mRes;
private final Handler mHandler;
+ private final InputMethodManagerInternal mInputMethodManagerInternal;
@NonNull
private final Handler mIoHandler;
@@ -343,8 +347,8 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
private int mCurrentUserId;
/** Holds all user related data */
- @GuardedBy("ImfLock.class")
- private UserDataRepository mUserDataRepository;
+ @SharedByAllUsersField
+ private final UserDataRepository mUserDataRepository;
final WindowManagerInternal mWindowManagerInternal;
private final ActivityManagerInternal mActivityManagerInternal;
@@ -648,7 +652,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
* Handles {@link Intent#ACTION_LOCALE_CHANGED}.
*
* <p>Note: For historical reasons, {@link Intent#ACTION_LOCALE_CHANGED} has been sent to all
- * the users. We should ignore this event if this is about any background user's locale.</p>
+ * the users.</p>
*/
void onActionLocaleChanged(@NonNull LocaleList prevLocales, @NonNull LocaleList newLocales) {
if (DEBUG) {
@@ -665,13 +669,14 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
AdditionalSubtypeMapRepository.get(userId),
DirectBootAwareness.AUTO);
InputMethodSettingsRepository.put(userId, settings);
+
+ if (mConcurrentMultiUserModeEnabled || userId == mCurrentUserId) {
+ postInputMethodSettingUpdatedLocked(true /* resetDefaultEnabledIme */, userId);
+ // If the locale is changed, needs to reset the default ime
+ resetDefaultImeLocked(mContext, userId);
+ updateFromSettingsLocked(true, userId);
+ }
}
- // TODO(b/305849394): Dispatch this to non-current users.
- final int userId = mCurrentUserId;
- postInputMethodSettingUpdatedLocked(true /* resetDefaultEnabledIme */, userId);
- // If the locale is changed, needs to reset the default ime
- resetDefaultImeLocked(mContext, userId);
- updateFromSettingsLocked(true, userId);
}
}
@@ -919,21 +924,58 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
* {@link SystemService} used to publish and manage the lifecycle of
* {@link InputMethodManagerService}.
*/
- public static final class Lifecycle extends SystemService {
+ public static final class Lifecycle extends SystemService
+ implements UserManagerInternal.UserLifecycleListener {
private final InputMethodManagerService mService;
-
public Lifecycle(Context context) {
- this(context, new InputMethodManagerService(context,
- shouldEnableConcurrentMultiUserMode(context)));
+ this(context, createServiceForProduction(context));
+
+ // For production code, hook up user lifecycle
+ mService.mUserManagerInternal.addUserLifecycleListener(this);
+
+ // Also schedule user init tasks onto an I/O thread.
+ initializeUsersAsync(context, mService.mIoHandler,
+ mService.mUserManagerInternal.getUserIds());
}
- public Lifecycle(
- Context context, @NonNull InputMethodManagerService inputMethodManagerService) {
+ @VisibleForTesting
+ Lifecycle(Context context, @NonNull InputMethodManagerService inputMethodManagerService) {
super(context);
mService = inputMethodManagerService;
}
+ /**
+ * Does initialization then instantiate {@link InputMethodManagerService} for production
+ * configurations.
+ *
+ * <p>We have this abstraction just because several unit tests directly initialize
+ * {@link InputMethodManagerService} with some mocked/emulated dependencies.</p>
+ *
+ * @param context {@link Context} to be used to set up
+ * @return {@link InputMethodManagerService} object to be used
+ */
+ @NonNull
+ private static InputMethodManagerService createServiceForProduction(
+ @NonNull Context context) {
+ // TODO(b/196206770): Disallow I/O on this thread. Currently it's needed for loading
+ // additional subtypes in switchUserOnHandlerLocked().
+ final ServiceThread thread = new ServiceThread(HANDLER_THREAD_NAME,
+ Process.THREAD_PRIORITY_FOREGROUND, true /* allowIo */);
+ thread.start();
+
+ final ServiceThread ioThread = new ServiceThread(PACKAGE_MONITOR_THREAD_NAME,
+ Process.THREAD_PRIORITY_FOREGROUND, true /* allowIo */);
+ ioThread.start();
+
+ SecureSettingsWrapper.setContentResolver(context.getContentResolver());
+
+ return new InputMethodManagerService(context,
+ shouldEnableConcurrentMultiUserMode(context), thread.getLooper(),
+ Handler.createAsync(ioThread.getLooper()),
+ null /* bindingControllerForTesting */);
+ }
+
@Override
public void onStart() {
mService.publishLocalService();
@@ -975,6 +1017,22 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
}
@Override
+ public void onUserCreated(UserInfo user, @Nullable Object token) {
+ // Called directly from UserManagerService. Do not block the calling thread.
+ initializeUsersAsync(mService.mContext, mService.mIoHandler, new int[user.id]);
+ }
+
+ @Override
+ public void onUserRemoved(UserInfo user) {
+ // Called directly from UserManagerService. Do not block the calling thread.
+ final int userId = user.id;
+ SecureSettingsWrapper.onUserRemoved(userId);
+ AdditionalSubtypeMapRepository.remove(userId, mService.mIoHandler);
+ InputMethodSettingsRepository.remove(userId);
+ mService.mUserDataRepository.remove(userId);
+ }
+
+ @Override
public void onUserUnlocking(@NonNull TargetUser user) {
// Called on ActivityManager thread.
SecureSettingsWrapper.onUserUnlocking(user.getUserIdentifier());
@@ -987,16 +1045,46 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
// Called on ActivityManager thread.
final int userId = user.getUserIdentifier();
SecureSettingsWrapper.onUserStarting(userId);
- synchronized (ImfLock.class) {
- mService.getUserData(userId);
- if (mService.mConcurrentMultiUserModeEnabled) {
- if (mService.mCurrentUserId != userId && mService.mSystemReady) {
- mService.initializeVisibleBackgroundUserLocked(userId);
+ mService.mIoHandler.post(() -> {
+ synchronized (ImfLock.class) {
+ if (mService.mConcurrentMultiUserModeEnabled) {
+ if (mService.mCurrentUserId != userId && mService.mSystemReady) {
+ mService.initializeVisibleBackgroundUserLocked(userId);
+ }
}
}
- }
+ });
}
+ @AnyThread
+ private static void initializeUsersAsync(
+ @NonNull Context context, @NonNull Handler ioHandler, @UserIdInt int[] userIds) {
+ ioHandler.post(() -> {
+ // We first create InputMethodMap for each user without loading AdditionalSubtypes.
+ final int numUsers = userIds.length;
+ final InputMethodMap[] rawMethodMaps = new InputMethodMap[numUsers];
+ for (int i = 0; i < numUsers; ++i) {
+ final int userId = userIds[i];
+ rawMethodMaps[i] = InputMethodManagerService.queryInputMethodServicesInternal(
+ context, userId, AdditionalSubtypeMap.EMPTY_MAP,
+ DirectBootAwareness.AUTO).getMethodMap();
+ }
+
+ // Then create full InputMethodMap for each user. Note that
+ // AdditionalSubtypeMapRepository#get() and InputMethodSettingsRepository#put()
+ // need to be called with ImfLock held (b/352387655).
+ // TODO(b/343601565): Avoid ImfLock after fixing b/352387655.
+ synchronized (ImfLock.class) {
+ for (int i = 0; i < numUsers; ++i) {
+ final int userId = userIds[i];
+ final var map = AdditionalSubtypeMapRepository.get(userId);
+ final var methodMap = rawMethodMaps[i].applyAdditionalSubtypes(map);
+ final var settings = InputMethodSettings.create(methodMap, userId);
+ InputMethodSettingsRepository.put(userId, settings);
+ }
+ }
+ });
+ }
}
void onUnlockUser(@UserIdInt int userId) {
@@ -1041,46 +1129,20 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
mHandler.post(task);
}
- public InputMethodManagerService(Context context,
- boolean concurrentMultiUserModeEnabled) {
- this(context, concurrentMultiUserModeEnabled, null, null, null);
- }
-
@VisibleForTesting
InputMethodManagerService(
Context context,
boolean concurrentMultiUserModeEnabled,
- @Nullable ServiceThread serviceThreadForTesting,
- @Nullable ServiceThread ioThreadForTesting,
+ @NonNull Looper uiLooper,
+ @NonNull Handler ioHandler,
@Nullable IntFunction<InputMethodBindingController> bindingControllerForTesting) {
synchronized (ImfLock.class) {
mConcurrentMultiUserModeEnabled = concurrentMultiUserModeEnabled;
mContext = context;
mRes = context.getResources();
- SecureSettingsWrapper.onStart(mContext);
- // TODO(b/196206770): Disallow I/O on this thread. Currently it's needed for loading
- // additional subtypes in switchUserOnHandlerLocked().
- final ServiceThread thread =
- serviceThreadForTesting != null
- ? serviceThreadForTesting
- : new ServiceThread(
- HANDLER_THREAD_NAME,
- Process.THREAD_PRIORITY_FOREGROUND,
- true /* allowIo */);
- thread.start();
- mHandler = Handler.createAsync(thread.getLooper(), this);
- {
- final ServiceThread ioThread =
- ioThreadForTesting != null
- ? ioThreadForTesting
- : new ServiceThread(
- PACKAGE_MONITOR_THREAD_NAME,
- Process.THREAD_PRIORITY_FOREGROUND,
- true /* allowIo */);
- ioThread.start();
- mIoHandler = Handler.createAsync(ioThread.getLooper());
- }
+ mHandler = Handler.createAsync(uiLooper, this);
+ mIoHandler = ioHandler;
SystemLocaleWrapper.onStart(context, this::onActionLocaleChanged, mHandler);
mImeTrackerService = new ImeTrackerService(mHandler);
mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
@@ -1095,26 +1157,13 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
mShowOngoingImeSwitcherForPhones = false;
- // Executing InputMethodSettingsRepository.initialize() does not mean that it
- // immediately becomes ready to return the up-to-date InputMethodSettings for each
- // running user, because we want to return from the constructor as early as possible so
- // as not to delay the system boot process.
- // Search for InputMethodSettingsRepository.put() to find where and when it's actually
- // being updated. In general IMMS should refrain from exposing the existence of IMEs
- // until systemReady().
- InputMethodSettingsRepository.initialize(mHandler, mContext);
- AdditionalSubtypeMapRepository.initialize(mHandler, mContext);
-
mCurrentUserId = mActivityManagerInternal.getCurrentUserId();
@SuppressWarnings("GuardedBy") final IntFunction<InputMethodBindingController>
bindingControllerFactory = userId -> new InputMethodBindingController(userId,
InputMethodManagerService.this);
- mUserDataRepository = new UserDataRepository(mHandler, mUserManagerInternal,
+ mUserDataRepository = new UserDataRepository(
bindingControllerForTesting != null ? bindingControllerForTesting
: bindingControllerFactory);
- for (int id : mUserManagerInternal.getUserIds()) {
- getUserData(id);
- }
mMenuController = new InputMethodMenuController(this);
mVisibilityStateComputer = new ImeVisibilityStateComputer(this);
@@ -1128,9 +1177,10 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
mNonPreemptibleInputMethods = mRes.getStringArray(
com.android.internal.R.array.config_nonPreemptibleInputMethods);
Runnable discardDelegationTextRunnable = () -> discardHandwritingDelegationText();
- mHwController = new HandwritingModeController(mContext, thread.getLooper(),
+ mHwController = new HandwritingModeController(mContext, uiLooper,
new InkWindowInitializer(), discardDelegationTextRunnable);
registerDeviceListenerAndCheckStylusSupport();
+ mInputMethodManagerInternal = new LocalServiceImpl();
}
}
@@ -4558,6 +4608,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
proto.write(BACK_DISPOSITION, bindingController.getBackDisposition());
proto.write(IME_WINDOW_VISIBILITY, bindingController.getImeWindowVis());
proto.write(SHOW_IME_WITH_HARD_KEYBOARD, mMenuController.getShowImeWithHardKeyboard());
+ proto.write(CONCURRENT_MULTI_USER_MODE_ENABLED, mConcurrentMultiUserModeEnabled);
proto.end(token);
}
}
@@ -5585,7 +5636,12 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
}
private void publishLocalService() {
- LocalServices.addService(InputMethodManagerInternal.class, new LocalServiceImpl());
+ LocalServices.addService(InputMethodManagerInternal.class, mInputMethodManagerInternal);
+ }
+
+ // TODO(b/352228316): Remove it once IMMIProxy is removed.
+ InputMethodManagerInternal getLocalService(){
+ return mInputMethodManagerInternal;
}
private final class LocalServiceImpl extends InputMethodManagerInternal {
@@ -6006,6 +6062,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
final InputMethodSettings settings = InputMethodSettingsRepository.get(userId);
final var userData = getUserData(userId);
p.println("Current Input Method Manager state:");
+ p.println(" concurrentMultiUserModeEnabled" + mConcurrentMultiUserModeEnabled);
final List<InputMethodInfo> methodList = settings.getMethodList();
int numImes = methodList.size();
p.println(" Input Methods:");
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodSettingsRepository.java b/services/core/java/com/android/server/inputmethod/InputMethodSettingsRepository.java
index 68924b5f370f..50ba36450bda 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodSettingsRepository.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodSettingsRepository.java
@@ -16,17 +16,12 @@
package com.android.server.inputmethod;
+import android.annotation.AnyThread;
import android.annotation.NonNull;
import android.annotation.UserIdInt;
-import android.content.Context;
-import android.content.pm.UserInfo;
-import android.os.Handler;
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.inputmethod.DirectBootAwareness;
-import com.android.server.LocalServices;
-import com.android.server.pm.UserManagerInternal;
final class InputMethodSettingsRepository {
@GuardedBy("ImfLock.class")
@@ -54,33 +49,10 @@ final class InputMethodSettingsRepository {
sPerUserMap.put(userId, obj);
}
- static void initialize(@NonNull Handler handler, @NonNull Context context) {
- final UserManagerInternal userManagerInternal =
- LocalServices.getService(UserManagerInternal.class);
- handler.post(() -> {
- userManagerInternal.addUserLifecycleListener(
- new UserManagerInternal.UserLifecycleListener() {
- @Override
- public void onUserRemoved(UserInfo user) {
- final int userId = user.id;
- handler.post(() -> {
- synchronized (ImfLock.class) {
- sPerUserMap.remove(userId);
- }
- });
- }
- });
- synchronized (ImfLock.class) {
- for (int userId : userManagerInternal.getUserIds()) {
- final InputMethodSettings settings =
- InputMethodManagerService.queryInputMethodServicesInternal(
- context,
- userId,
- AdditionalSubtypeMapRepository.get(userId),
- DirectBootAwareness.AUTO);
- put(userId, settings);
- }
- }
- });
+ @AnyThread
+ static void remove(@UserIdInt int userId) {
+ synchronized (ImfLock.class) {
+ sPerUserMap.remove(userId);
+ }
}
}
diff --git a/services/core/java/com/android/server/inputmethod/SecureSettingsWrapper.java b/services/core/java/com/android/server/inputmethod/SecureSettingsWrapper.java
index 4764e4fadd6e..e7cff20ea2cb 100644
--- a/services/core/java/com/android/server/inputmethod/SecureSettingsWrapper.java
+++ b/services/core/java/com/android/server/inputmethod/SecureSettingsWrapper.java
@@ -20,10 +20,7 @@ import android.annotation.AnyThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
-import android.app.ActivityManagerInternal;
import android.content.ContentResolver;
-import android.content.Context;
-import android.content.pm.UserInfo;
import android.provider.Settings;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -321,30 +318,13 @@ final class SecureSettingsWrapper {
}
/**
- * Called when {@link InputMethodManagerService} is starting.
+ * Called when the system is starting.
*
- * @param context the {@link Context} to be used.
+ * @param contentResolver the {@link ContentResolver} to be used
*/
@AnyThread
- static void onStart(@NonNull Context context) {
- sContentResolver = context.getContentResolver();
-
- final int userId = LocalServices.getService(ActivityManagerInternal.class)
- .getCurrentUserId();
- final UserManagerInternal userManagerInternal =
- LocalServices.getService(UserManagerInternal.class);
- putOrGet(userId, createImpl(userManagerInternal, userId));
-
- userManagerInternal.addUserLifecycleListener(
- new UserManagerInternal.UserLifecycleListener() {
- @Override
- public void onUserRemoved(UserInfo user) {
- synchronized (sUserMap) {
- sUserMap.remove(userId);
- }
- }
- }
- );
+ static void setContentResolver(@NonNull ContentResolver contentResolver) {
+ sContentResolver = contentResolver;
}
/**
@@ -377,6 +357,18 @@ final class SecureSettingsWrapper {
}
/**
+ * Called when a user is being removed.
+ *
+ * @param userId the ID of the user whose storage is being removed.
+ */
+ @AnyThread
+ static void onUserRemoved(@UserIdInt int userId) {
+ synchronized (sUserMap) {
+ sUserMap.remove(userId);
+ }
+ }
+
+ /**
* Put the given string {@code value} to {@code key}.
*
* @param key a secure settings key.
diff --git a/services/core/java/com/android/server/inputmethod/UserDataRepository.java b/services/core/java/com/android/server/inputmethod/UserDataRepository.java
index 59411ad71bc0..98d7548d3dd2 100644
--- a/services/core/java/com/android/server/inputmethod/UserDataRepository.java
+++ b/services/core/java/com/android/server/inputmethod/UserDataRepository.java
@@ -16,11 +16,10 @@
package com.android.server.inputmethod;
+import android.annotation.AnyThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
-import android.content.pm.UserInfo;
-import android.os.Handler;
import android.util.SparseArray;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.ImeTracker;
@@ -29,62 +28,63 @@ import android.window.ImeOnBackInvokedDispatcher;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.inputmethod.IRemoteAccessibilityInputConnection;
import com.android.internal.inputmethod.IRemoteInputConnection;
-import com.android.server.pm.UserManagerInternal;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.function.Consumer;
import java.util.function.IntFunction;
final class UserDataRepository {
- @GuardedBy("ImfLock.class")
+ private final ReentrantReadWriteLock mUserDataLock = new ReentrantReadWriteLock();
+
+ @GuardedBy("mUserDataLock")
private final SparseArray<UserData> mUserData = new SparseArray<>();
private final IntFunction<InputMethodBindingController> mBindingControllerFactory;
- @GuardedBy("ImfLock.class")
+ @AnyThread
@NonNull
UserData getOrCreate(@UserIdInt int userId) {
- UserData userData = mUserData.get(userId);
- if (userData == null) {
- userData = new UserData(userId, mBindingControllerFactory.apply(userId));
- mUserData.put(userId, userData);
+ mUserDataLock.writeLock().lock();
+ try {
+ UserData userData = mUserData.get(userId);
+ if (userData == null) {
+ userData = new UserData(userId, mBindingControllerFactory.apply(userId));
+ mUserData.put(userId, userData);
+ }
+ return userData;
+ } finally {
+ mUserDataLock.writeLock().unlock();
}
- return userData;
}
- @GuardedBy("ImfLock.class")
+ @AnyThread
void forAllUserData(Consumer<UserData> consumer) {
- for (int i = 0; i < mUserData.size(); i++) {
- consumer.accept(mUserData.valueAt(i));
+ final SparseArray<UserData> copiedArray;
+ mUserDataLock.readLock().lock();
+ try {
+ copiedArray = mUserData.clone();
+ } finally {
+ mUserDataLock.readLock().unlock();
+ }
+ for (int i = 0; i < copiedArray.size(); i++) {
+ consumer.accept(copiedArray.valueAt(i));
}
}
UserDataRepository(
- @NonNull Handler handler, @NonNull UserManagerInternal userManagerInternal,
@NonNull IntFunction<InputMethodBindingController> bindingControllerFactory) {
mBindingControllerFactory = bindingControllerFactory;
- userManagerInternal.addUserLifecycleListener(
- new UserManagerInternal.UserLifecycleListener() {
- @Override
- public void onUserRemoved(UserInfo user) {
- final int userId = user.id;
- handler.post(() -> {
- synchronized (ImfLock.class) {
- mUserData.remove(userId);
- }
- });
- }
-
- @Override
- public void onUserCreated(UserInfo user, Object unusedToken) {
- final int userId = user.id;
- handler.post(() -> {
- synchronized (ImfLock.class) {
- getOrCreate(userId);
- }
- });
- }
- });
+ }
+
+ @AnyThread
+ void remove(@UserIdInt int userId) {
+ mUserDataLock.writeLock().lock();
+ try {
+ mUserData.remove(userId);
+ } finally {
+ mUserDataLock.writeLock().unlock();
+ }
}
/** Placeholder for all IMMS user specific fields */
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubTestModeManager.java b/services/core/java/com/android/server/location/contexthub/ContextHubTestModeManager.java
index e50324eb7c83..f2714dbd7e5f 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubTestModeManager.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubTestModeManager.java
@@ -29,19 +29,22 @@ import java.util.Random;
public class ContextHubTestModeManager {
private static final String TAG = "ContextHubTestModeManager";
- /** Probability (in percent) of duplicating a message. */
- private static final int MESSAGE_DROP_PROBABILITY_PERCENT = 20;
+ /** Probability of duplicating a message. */
+ private static final double MESSAGE_DROP_PROBABILITY = 0.05;
- /** Probability (in percent) of duplicating a message. */
- private static final int MESSAGE_DUPLICATION_PROBABILITY_PERCENT = 20;
+ /** Probability of duplicating a message. */
+ private static final double MESSAGE_DUPLICATION_PROBABILITY = 0.05;
- /** The number of total messages to send when the duplicate event happens. */
+ /** The number of total messages to send when the duplication 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;
+ /**
+ * The seed for the random number generator. This is used to make the
+ * test more deterministic.
+ */
+ private static final long SEED = 0xDEADBEEF;
- private final Random mRandom = new Random();
+ private final Random mRandom = new Random(SEED);
/**
* @return whether the message was handled
@@ -50,8 +53,7 @@ public class ContextHubTestModeManager {
public boolean handleNanoappMessage(Runnable handleMessage, NanoAppMessage message) {
if (Flags.reliableMessageDuplicateDetectionService()
&& message.isReliable()
- && mRandom.nextInt(MAX_PROBABILITY_PERCENT)
- < MESSAGE_DUPLICATION_PROBABILITY_PERCENT) {
+ && mRandom.nextDouble() < MESSAGE_DUPLICATION_PROBABILITY) {
Log.i(TAG, "[TEST MODE] Duplicating message ("
+ NUM_MESSAGES_TO_DUPLICATE
+ " sends) with message sequence number: "
@@ -71,8 +73,7 @@ public class ContextHubTestModeManager {
public boolean sendMessageToContextHub(NanoAppMessage message) {
if (Flags.reliableMessageRetrySupportService()
&& message.isReliable()
- && mRandom.nextInt(MAX_PROBABILITY_PERCENT)
- < MESSAGE_DROP_PROBABILITY_PERCENT) {
+ && mRandom.nextDouble() < MESSAGE_DROP_PROBABILITY) {
Log.i(TAG, "[TEST MODE] Dropping message with message sequence number: "
+ message.getMessageSequenceNumber());
return true;
diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
index e3d5c54f1d5e..803b125cbabc 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
@@ -17,6 +17,7 @@
package com.android.server.media.projection;
import static android.Manifest.permission.MANAGE_MEDIA_PROJECTION;
+import static android.Manifest.permission.RECORD_SENSITIVE_CONTENT;
import static android.app.ActivityManagerInternal.MEDIA_PROJECTION_TOKEN_EVENT_CREATED;
import static android.app.ActivityManagerInternal.MEDIA_PROJECTION_TOKEN_EVENT_DESTROYED;
import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
@@ -34,10 +35,12 @@ import android.Manifest;
import android.annotation.EnforcePermission;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.app.ActivityManagerInternal;
import android.app.ActivityOptions.LaunchCookie;
import android.app.AppOpsManager;
import android.app.IProcessObserver;
+import android.app.KeyguardManager;
import android.app.compat.CompatChanges;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledSince;
@@ -78,6 +81,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
import com.android.server.LocalServices;
+import com.android.server.SystemConfig;
import com.android.server.SystemService;
import com.android.server.Watchdog;
import com.android.server.wm.WindowManagerInternal;
@@ -132,6 +136,7 @@ public final class MediaProjectionManagerService extends SystemService
private final ActivityManagerInternal mActivityManagerInternal;
private final PackageManager mPackageManager;
private final WindowManagerInternal mWmInternal;
+ private final KeyguardManager mKeyguardManager;
private final MediaRouter mMediaRouter;
private final MediaRouterCallback mMediaRouterCallback;
@@ -147,7 +152,9 @@ public final class MediaProjectionManagerService extends SystemService
this(context, new Injector());
}
- @VisibleForTesting MediaProjectionManagerService(Context context, Injector injector) {
+ @RequiresPermission(Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE)
+ @VisibleForTesting
+ MediaProjectionManagerService(Context context, Injector injector) {
super(context);
mContext = context;
mInjector = injector;
@@ -163,9 +170,47 @@ public final class MediaProjectionManagerService extends SystemService
mMediaRouter = (MediaRouter) mContext.getSystemService(Context.MEDIA_ROUTER_SERVICE);
mMediaRouterCallback = new MediaRouterCallback();
mMediaProjectionMetricsLogger = injector.mediaProjectionMetricsLogger(context);
+ mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
+ mKeyguardManager.addKeyguardLockedStateListener(
+ mContext.getMainExecutor(), this::onKeyguardLockedStateChanged);
Watchdog.getInstance().addMonitor(this);
}
+ /**
+ * In order to record the keyguard, the MediaProjection package must be either:
+ * - a holder of RECORD_SENSITIVE_CONTENT permission, or
+ * - be one of the bugreport whitelisted packages
+ */
+ private boolean canCaptureKeyguard() {
+ if (!android.companion.virtualdevice.flags.Flags.mediaProjectionKeyguardRestrictions()) {
+ return true;
+ }
+ synchronized (mLock) {
+ if (mProjectionGrant == null || mProjectionGrant.packageName == null) {
+ return false;
+ }
+ if (mPackageManager.checkPermission(RECORD_SENSITIVE_CONTENT,
+ mProjectionGrant.packageName)
+ == PackageManager.PERMISSION_GRANTED) {
+ return true;
+ }
+ return SystemConfig.getInstance().getBugreportWhitelistedPackages()
+ .contains(mProjectionGrant.packageName);
+ }
+ }
+
+ @VisibleForTesting
+ void onKeyguardLockedStateChanged(boolean isKeyguardLocked) {
+ if (!isKeyguardLocked) return;
+ synchronized (mLock) {
+ if (mProjectionGrant != null && !canCaptureKeyguard()) {
+ Slog.d(TAG, "Content Recording: Stopped MediaProjection"
+ + " due to keyguard lock");
+ mProjectionGrant.stop();
+ }
+ }
+ }
+
/** Functional interface for providing time. */
@VisibleForTesting
interface Clock {
@@ -1252,6 +1297,11 @@ public final class MediaProjectionManagerService extends SystemService
@Override
public void notifyVirtualDisplayCreated(int displayId) {
notifyVirtualDisplayCreated_enforcePermission();
+ if (mKeyguardManager.isKeyguardLocked() && !canCaptureKeyguard()) {
+ Slog.w(TAG, "Content Recording: Keyguard locked, aborting MediaProjection");
+ stop();
+ return;
+ }
synchronized (mLock) {
mVirtualDisplayId = displayId;
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 1c40f44b7b78..9e53cc357ea4 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -8658,8 +8658,7 @@ public class NotificationManagerService extends SystemService {
mAttentionHelper.updateLightsLocked();
if (mShortcutHelper != null) {
mShortcutHelper.maybeListenForShortcutChangesForBubbles(r,
- true /* isRemoved */,
- mHandler);
+ true /* isRemoved */);
}
} else {
if (notificationForceGrouping()) {
@@ -9116,8 +9115,7 @@ public class NotificationManagerService extends SystemService {
if (mShortcutHelper != null) {
mShortcutHelper.maybeListenForShortcutChangesForBubbles(r,
- false /* isRemoved */,
- mHandler);
+ false /* isRemoved */);
}
maybeRecordInterruptionLocked(r);
diff --git a/services/core/java/com/android/server/notification/ShortcutHelper.java b/services/core/java/com/android/server/notification/ShortcutHelper.java
index 86dcecf9290a..857e3198d55b 100644
--- a/services/core/java/com/android/server/notification/ShortcutHelper.java
+++ b/services/core/java/com/android/server/notification/ShortcutHelper.java
@@ -27,7 +27,6 @@ import android.content.pm.LauncherApps;
import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutServiceInternal;
import android.os.Binder;
-import android.os.Handler;
import android.os.UserHandle;
import android.os.UserManager;
import android.text.TextUtils;
@@ -65,85 +64,34 @@ public class ShortcutHelper {
void onShortcutRemoved(String key);
}
+ private final ShortcutListener mShortcutListener;
private LauncherApps mLauncherAppsService;
- private ShortcutListener mShortcutListener;
private ShortcutServiceInternal mShortcutServiceInternal;
private UserManager mUserManager;
- // Key: packageName Value: <shortcutId, notifId>
- private HashMap<String, HashMap<String, String>> mActiveShortcutBubbles = new HashMap<>();
- private boolean mLauncherAppsCallbackRegistered;
+ // Key: packageName|userId Value: <shortcutId, notifId>
+ private final HashMap<String, HashMap<String, String>> mActiveShortcutBubbles = new HashMap<>();
+ private boolean mShortcutChangedCallbackRegistered;
// Bubbles can be created based on a shortcut, we need to listen for changes to
// that shortcut so that we may update the bubble appropriately.
- private final LauncherApps.Callback mLauncherAppsCallback = new LauncherApps.Callback() {
- @Override
- public void onPackageRemoved(String packageName, UserHandle user) {
- }
-
- @Override
- public void onPackageAdded(String packageName, UserHandle user) {
- }
-
- @Override
- public void onPackageChanged(String packageName, UserHandle user) {
- }
-
- @Override
- public void onPackagesAvailable(String[] packageNames, UserHandle user,
- boolean replacing) {
- }
-
- @Override
- public void onPackagesUnavailable(String[] packageNames, UserHandle user,
- boolean replacing) {
- }
+ private final LauncherApps.ShortcutChangeCallback mShortcutChangeCallback =
+ new LauncherApps.ShortcutChangeCallback() {
- @Override
- public void onShortcutsChanged(@NonNull String packageName,
- @NonNull List<ShortcutInfo> shortcuts, @NonNull UserHandle user) {
- HashMap<String, String> shortcutBubbles = mActiveShortcutBubbles.get(packageName);
- ArrayList<String> bubbleKeysToRemove = new ArrayList<>();
- if (shortcutBubbles != null) {
- // Copy to avoid a concurrent modification exception when we remove bubbles from
- // shortcutBubbles.
- final Set<String> shortcutIds = new HashSet<>(shortcutBubbles.keySet());
-
- // If we can't find one of our bubbles in the shortcut list, that bubble needs
- // to be removed.
- for (String shortcutId : shortcutIds) {
- boolean foundShortcut = false;
- for (int i = 0; i < shortcuts.size(); i++) {
- if (shortcuts.get(i).getId().equals(shortcutId)) {
- foundShortcut = true;
- break;
- }
- }
- if (!foundShortcut) {
- bubbleKeysToRemove.add(shortcutBubbles.get(shortcutId));
- shortcutBubbles.remove(shortcutId);
- if (shortcutBubbles.isEmpty()) {
- mActiveShortcutBubbles.remove(packageName);
- if (mLauncherAppsCallbackRegistered
- && mActiveShortcutBubbles.isEmpty()) {
- mLauncherAppsService.unregisterCallback(mLauncherAppsCallback);
- mLauncherAppsCallbackRegistered = false;
- }
- }
- }
+ @Override
+ public void onShortcutsAddedOrUpdated(@NonNull String packageName,
+ @NonNull List<ShortcutInfo> shortcuts, @NonNull UserHandle user) {
}
- }
- // Let NoMan know about the updates
- for (int i = 0; i < bubbleKeysToRemove.size(); i++) {
- // update flag bubble
- String bubbleKey = bubbleKeysToRemove.get(i);
- if (mShortcutListener != null) {
- mShortcutListener.onShortcutRemoved(bubbleKey);
+ public void onShortcutsRemoved(@NonNull String packageName,
+ @NonNull List<ShortcutInfo> removedShortcuts, @NonNull UserHandle user) {
+ final String packageUserKey = getPackageUserKey(packageName, user);
+ if (mActiveShortcutBubbles.get(packageUserKey) == null) return;
+ for (ShortcutInfo info : removedShortcuts) {
+ onShortcutRemoved(packageUserKey, info.getId());
+ }
}
- }
- }
- };
+ };
ShortcutHelper(LauncherApps launcherApps, ShortcutListener listener,
ShortcutServiceInternal shortcutServiceInternal, UserManager userManager) {
@@ -172,14 +120,14 @@ public class ShortcutHelper {
* Returns whether the given shortcut info is a conversation shortcut.
*/
public static boolean isConversationShortcut(
- ShortcutInfo shortcutInfo, ShortcutServiceInternal mShortcutServiceInternal,
+ ShortcutInfo shortcutInfo, ShortcutServiceInternal shortcutServiceInternal,
int callingUserId) {
if (shortcutInfo == null || !shortcutInfo.isLongLived() || !shortcutInfo.isEnabled()) {
return false;
}
// TODO (b/155016294) uncomment when sharing shortcuts are required
/*
- mShortcutServiceInternal.isSharingShortcut(callingUserId, "android",
+ shortcutServiceInternal.isSharingShortcut(callingUserId, "android",
shortcutInfo.getPackage(), shortcutInfo.getId(), shortcutInfo.getUserId(),
SHARING_FILTER);
*/
@@ -233,34 +181,30 @@ public class ShortcutHelper {
*
* @param r the notification record to check
* @param removedNotification true if this notification is being removed
- * @param handler handler to register the callback with
*/
void maybeListenForShortcutChangesForBubbles(NotificationRecord r,
- boolean removedNotification,
- Handler handler) {
+ boolean removedNotification) {
final String shortcutId = r.getNotification().getBubbleMetadata() != null
? r.getNotification().getBubbleMetadata().getShortcutId()
: null;
+ final String packageUserKey = getPackageUserKey(r.getSbn().getPackageName(), r.getUser());
if (!removedNotification
&& !TextUtils.isEmpty(shortcutId)
&& r.getShortcutInfo() != null
&& r.getShortcutInfo().getId().equals(shortcutId)) {
// Must track shortcut based bubbles in case the shortcut is removed
HashMap<String, String> packageBubbles = mActiveShortcutBubbles.get(
- r.getSbn().getPackageName());
+ packageUserKey);
if (packageBubbles == null) {
packageBubbles = new HashMap<>();
}
packageBubbles.put(shortcutId, r.getKey());
- mActiveShortcutBubbles.put(r.getSbn().getPackageName(), packageBubbles);
- if (!mLauncherAppsCallbackRegistered) {
- mLauncherAppsService.registerCallback(mLauncherAppsCallback, handler);
- mLauncherAppsCallbackRegistered = true;
- }
+ mActiveShortcutBubbles.put(packageUserKey, packageBubbles);
+ registerCallbackIfNeeded();
} else {
// No longer track shortcut
HashMap<String, String> packageBubbles = mActiveShortcutBubbles.get(
- r.getSbn().getPackageName());
+ packageUserKey);
if (packageBubbles != null) {
if (!TextUtils.isEmpty(shortcutId)) {
packageBubbles.remove(shortcutId);
@@ -278,20 +222,62 @@ public class ShortcutHelper {
}
}
if (packageBubbles.isEmpty()) {
- mActiveShortcutBubbles.remove(r.getSbn().getPackageName());
+ mActiveShortcutBubbles.remove(packageUserKey);
}
}
- if (mLauncherAppsCallbackRegistered && mActiveShortcutBubbles.isEmpty()) {
- mLauncherAppsService.unregisterCallback(mLauncherAppsCallback);
- mLauncherAppsCallbackRegistered = false;
+ unregisterCallbackIfNeeded();
+ }
+ }
+
+ private String getPackageUserKey(String packageName, UserHandle user) {
+ return packageName + "|" + user.getIdentifier();
+ }
+
+ private void onShortcutRemoved(String packageUserKey, String shortcutId) {
+ HashMap<String, String> shortcutBubbles = mActiveShortcutBubbles.get(packageUserKey);
+ ArrayList<String> bubbleKeysToRemove = new ArrayList<>();
+ if (shortcutBubbles != null) {
+ if (shortcutBubbles.containsKey(shortcutId)) {
+ bubbleKeysToRemove.add(shortcutBubbles.get(shortcutId));
+ shortcutBubbles.remove(shortcutId);
+ if (shortcutBubbles.isEmpty()) {
+ mActiveShortcutBubbles.remove(packageUserKey);
+ unregisterCallbackIfNeeded();
+ }
}
+ notifyNoMan(bubbleKeysToRemove);
+ }
+ }
+
+ private void registerCallbackIfNeeded() {
+ if (!mShortcutChangedCallbackRegistered) {
+ mShortcutChangedCallbackRegistered = true;
+ mShortcutServiceInternal.addShortcutChangeCallback(mShortcutChangeCallback);
+ }
+ }
+
+ private void unregisterCallbackIfNeeded() {
+ if (mShortcutChangedCallbackRegistered && mActiveShortcutBubbles.isEmpty()) {
+ mShortcutServiceInternal.removeShortcutChangeCallback(mShortcutChangeCallback);
+ mShortcutChangedCallbackRegistered = false;
}
}
void destroy() {
- if (mLauncherAppsCallbackRegistered) {
- mLauncherAppsService.unregisterCallback(mLauncherAppsCallback);
- mLauncherAppsCallbackRegistered = false;
+ if (mShortcutChangedCallbackRegistered) {
+ mShortcutServiceInternal.removeShortcutChangeCallback(mShortcutChangeCallback);
+ mShortcutChangedCallbackRegistered = false;
+ }
+ }
+
+ private void notifyNoMan(List<String> bubbleKeysToRemove) {
+ // Let NoMan know about the updates
+ for (int i = 0; i < bubbleKeysToRemove.size(); i++) {
+ // update flag bubble
+ String bubbleKey = bubbleKeysToRemove.get(i);
+ if (mShortcutListener != null) {
+ mShortcutListener.onShortcutRemoved(bubbleKey);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/notification/ZenModeEventLogger.java b/services/core/java/com/android/server/notification/ZenModeEventLogger.java
index ec5d96df3430..4a82057ed2a2 100644
--- a/services/core/java/com/android/server/notification/ZenModeEventLogger.java
+++ b/services/core/java/com/android/server/notification/ZenModeEventLogger.java
@@ -106,11 +106,11 @@ class ZenModeEventLogger {
/**
* Potentially log a zen mode change if the provided config and policy changes warrant it.
*
- * @param prevInfo ZenModeInfo (zen mode setting, config, policy) prior to this change
- * @param newInfo ZenModeInfo after this change takes effect
- * @param callingUid the calling UID associated with the change; may be used to attribute the
- * change to a particular package or determine if this is a user action
- * @param origin The origin of the Zen change.
+ * @param prevInfo ZenModeInfo (zen mode setting, config, policy) prior to this change
+ * @param newInfo ZenModeInfo after this change takes effect
+ * @param callingUid the calling UID associated with the change; may be used to attribute the
+ * change to a particular package or determine if this is a user action
+ * @param origin The origin of the Zen change.
*/
public final void maybeLogZenChange(ZenModeInfo prevInfo, ZenModeInfo newInfo, int callingUid,
@ConfigChangeOrigin int origin) {
@@ -127,6 +127,9 @@ class ZenModeEventLogger {
/**
* Reassign callingUid in mChangeState if we have more specific information that warrants it
* (for instance, if the change is automatic and due to an automatic rule change).
+ *
+ * <p>When Flags.modesUi() is enabled, we reassign the calling UID to the package UID in all
+ * changes whose source is not system or system UI, as long as there is only one rule changed.
*/
private void maybeReassignCallingUid() {
int userId = Process.INVALID_UID;
@@ -145,12 +148,23 @@ class ZenModeEventLogger {
userId = mChangeState.mNewConfig.user; // mNewConfig must not be null if enabler exists
}
- // The conditions where we should consider reassigning UID for an automatic rule change:
+ // The conditions where we should consider reassigning UID for an automatic rule change
+ // (pre-modes_ui):
// - we've determined it's not a user action
// - our current best guess is that the calling uid is system/sysui
+ // When Flags.modesUi() is true, we get the package UID for the changed rule, as long as:
+ // - the change does not originate from the system based on change origin
+ // - there is only one rule changed
if (mChangeState.getChangedRuleType() == RULE_TYPE_AUTOMATIC) {
- if (mChangeState.getIsUserAction() || !mChangeState.isFromSystemOrSystemUi()) {
- return;
+ if (Flags.modesUi()) {
+ // ignore anything whose origin is system
+ if (mChangeState.isFromSystemOrSystemUi()) {
+ return;
+ }
+ } else {
+ if (mChangeState.getIsUserAction() || !mChangeState.isFromSystemOrSystemUi()) {
+ return;
+ }
}
// Only try to get the package UID if there's exactly one changed automatic rule. If
@@ -202,7 +216,8 @@ class ZenModeEventLogger {
/* int32 package_uid = 7 */ mChangeState.getPackageUid(),
/* DNDPolicyProto current_policy = 8 */ mChangeState.getDNDPolicyProto(),
/* bool are_channels_bypassing = 9 */ mChangeState.getAreChannelsBypassing(),
- /* ActiveRuleType active_rule_types = 10 */ mChangeState.getActiveRuleTypes());
+ /* ActiveRuleType active_rule_types = 10 */ mChangeState.getActiveRuleTypes(),
+ /* ChangeOrigin change_origin = 11 */ mChangeState.getChangeOrigin());
}
/**
@@ -235,7 +250,8 @@ class ZenModeEventLogger {
ZenModeConfig mPrevConfig, mNewConfig;
NotificationManager.Policy mPrevPolicy, mNewPolicy;
int mCallingUid = Process.INVALID_UID;
- @ConfigChangeOrigin int mOrigin = ZenModeConfig.UPDATE_ORIGIN_UNKNOWN;
+ @ConfigChangeOrigin
+ int mOrigin = ZenModeConfig.UPDATE_ORIGIN_UNKNOWN;
private void init(ZenModeInfo prevInfo, ZenModeInfo newInfo, int callingUid,
@ConfigChangeOrigin int origin) {
@@ -388,7 +404,8 @@ class ZenModeEventLogger {
* rules available.
*/
@SuppressLint("WrongConstant") // special case for log-only type on manual rule
- @NonNull List<ZenRule> activeRulesList(ZenModeConfig config) {
+ @NonNull
+ List<ZenRule> activeRulesList(ZenModeConfig config) {
ArrayList<ZenRule> rules = new ArrayList<>();
if (config == null) {
return rules;
@@ -548,6 +565,17 @@ class ZenModeEventLogger {
}
/**
+ * Get the config change origin associated with this change, which is stored in mOrigin.
+ * Only useable if modes_ui is true.
+ */
+ int getChangeOrigin() {
+ if (Flags.modesUi()) {
+ return mOrigin;
+ }
+ return 0;
+ }
+
+ /**
* Convert the new policy to a DNDPolicyProto format for output in logs.
*
* <p>If {@code mNewZenMode} is {@code ZEN_MODE_OFF} (which can mean either no rules
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index 009e9b862b0f..303371bd9a92 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -801,8 +801,9 @@ final class InstallPackageHelper {
try {
final BroadcastOptions options = BroadcastOptions.makeBasic();
options.setPendingIntentBackgroundActivityLaunchAllowed(false);
- target.sendIntent(context, 0, fillIn, null /* onFinished*/, null /* handler */,
- null /* requiredPermission */, options.toBundle());
+ target.sendIntent(context, 0, fillIn,
+ null /* requiredPermission */, options.toBundle(),
+ null /* executor */, null /* onFinished*/);
} catch (IntentSender.SendIntentException ignored) {
}
}
@@ -2628,18 +2629,28 @@ final class InstallPackageHelper {
String packageName = pkgLite.packageName;
synchronized (mPm.mLock) {
- // Package which currently owns the data that the new package will own if installed.
- // If an app is uninstalled while keeping data (e.g. adb uninstall -k), installedPkg
- // will be null whereas dataOwnerPkg will contain information about the package
- // which was uninstalled while keeping its data.
- AndroidPackage dataOwnerPkg = mPm.mPackages.get(packageName);
PackageSetting dataOwnerPs = mPm.mSettings.getPackageLPr(packageName);
- if (dataOwnerPkg == null) {
- if (dataOwnerPs != null) {
- dataOwnerPkg = dataOwnerPs.getPkg();
+ if (dataOwnerPs == null) {
+ if (requiredInstalledVersionCode != PackageManager.VERSION_CODE_HIGHEST) {
+ String errorMsg = "Required installed version code was "
+ + requiredInstalledVersionCode
+ + " but package is not installed";
+ Slog.w(TAG, errorMsg);
+ return Pair.create(
+ PackageManager.INSTALL_FAILED_WRONG_INSTALLED_VERSION, errorMsg);
}
+ // The package doesn't exist in the system, don't need to check the version
+ // replacing.
+ return Pair.create(PackageManager.INSTALL_SUCCEEDED, null);
}
+ // Package which currently owns the data that the new package will own if installed.
+ // If an app is uninstalled while keeping data (e.g. adb uninstall -k), dataOwnerPkg
+ // will be null whereas dataOwnerPs will contain information about the package
+ // which was uninstalled while keeping its data. The AndroidPackage object that the
+ // PackageSetting refers to is the same object that is stored in mPackages.
+ AndroidPackage dataOwnerPkg = dataOwnerPs.getPkg();
+
if (requiredInstalledVersionCode != PackageManager.VERSION_CODE_HIGHEST) {
if (dataOwnerPkg == null) {
String errorMsg = "Required installed version code was "
@@ -2661,7 +2672,27 @@ final class InstallPackageHelper {
}
}
- if (dataOwnerPkg != null && !dataOwnerPkg.isSdkLibrary()) {
+ // If dataOwnerPkg is null but dataOwnerPs is not null, there is always data on
+ // some users. Wwe should do the downgrade check. E.g. DELETE_KEEP_DATA and
+ // archived apps
+ if (dataOwnerPkg == null) {
+ if (!PackageManagerServiceUtils.isDowngradePermitted(installFlags,
+ dataOwnerPs.isDebuggable())) {
+ // The data exists on some users and downgrade is not permitted; a lower
+ // version of the app will not be allowed.
+ try {
+ PackageManagerServiceUtils.checkDowngrade(dataOwnerPs, pkgLite);
+ } catch (PackageManagerException e) {
+ String errorMsg = "Downgrade detected on app uninstalled with"
+ + " DELETE_KEEP_DATA: " + e.getMessage();
+ Slog.w(TAG, errorMsg);
+ return Pair.create(
+ PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE, errorMsg);
+ }
+ }
+ // dataOwnerPs.getPkg() is not null on system apps case. Don't need to consider
+ // system apps case like below.
+ } else if (dataOwnerPkg != null && !dataOwnerPkg.isSdkLibrary()) {
if (!PackageManagerServiceUtils.isDowngradePermitted(installFlags,
dataOwnerPkg.isDebuggable())) {
// Downgrade is not permitted; a lower version of the app will not be allowed
diff --git a/services/core/java/com/android/server/pm/PackageArchiver.java b/services/core/java/com/android/server/pm/PackageArchiver.java
index 0d1095f5656d..6b7b702b9157 100644
--- a/services/core/java/com/android/server/pm/PackageArchiver.java
+++ b/services/core/java/com/android/server/pm/PackageArchiver.java
@@ -1194,8 +1194,9 @@ public class PackageArchiver {
MODE_BACKGROUND_ACTIVITY_START_DENIED);
for (IntentSender intentSender : unarchiveIntentSenders) {
try {
- intentSender.sendIntent(mContext, 0, broadcastIntent, /* onFinished= */ null,
- /* handler= */ null, /* requiredPermission= */ null, options.toBundle());
+ intentSender.sendIntent(mContext, 0, broadcastIntent,
+ /* requiredPermission */ null, options.toBundle(),
+ /* executor */ null, /* onFinished */ null);
} catch (IntentSender.SendIntentException e) {
Slog.e(TAG, TextUtils.formatSimple("Failed to send unarchive intent"), e);
} finally {
@@ -1328,8 +1329,9 @@ public class PackageArchiver {
final BroadcastOptions options = BroadcastOptions.makeBasic();
options.setPendingIntentBackgroundActivityStartMode(
MODE_BACKGROUND_ACTIVITY_START_DENIED);
- statusReceiver.sendIntent(mContext, 0, intent, /* onFinished= */ null,
- /* handler= */ null, /* requiredPermission= */ null, options.toBundle());
+ statusReceiver.sendIntent(mContext, 0, intent,
+ /* requiredPermission */ null, options.toBundle(),
+ /* executor */ null, /* onFinished */ null);
} catch (IntentSender.SendIntentException e) {
Slog.e(
TAG,
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index b93dcdc93a82..f615ca1da2e2 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -1581,8 +1581,9 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
try {
final BroadcastOptions options = BroadcastOptions.makeBasic();
options.setPendingIntentBackgroundActivityLaunchAllowed(false);
- callback.sendIntent(mContext, 0, intent, null /* onFinished*/,
- null /* handler */, null /* requiredPermission */, options.toBundle());
+ callback.sendIntent(mContext, 0, intent,
+ null /* requiredPermission */, options.toBundle(),
+ null /* executor */, null /* onFinished*/);
} catch (SendIntentException ignore) {
}
});
@@ -1912,8 +1913,9 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
try {
final BroadcastOptions options = BroadcastOptions.makeBasic();
options.setPendingIntentBackgroundActivityLaunchAllowed(false);
- mTarget.sendIntent(mContext, 0, fillIn, null /* onFinished*/,
- null /* handler */, null /* requiredPermission */, options.toBundle());
+ mTarget.sendIntent(mContext, 0, fillIn,
+ null /* requiredPermission */, options.toBundle(),
+ null /* executor */, null /* onFinished*/);
} catch (SendIntentException ignored) {
}
}
@@ -1945,8 +1947,9 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
try {
final BroadcastOptions options = BroadcastOptions.makeBasic();
options.setPendingIntentBackgroundActivityLaunchAllowed(false);
- mTarget.sendIntent(mContext, 0, fillIn, null /* onFinished*/,
- null /* handler */, null /* requiredPermission */, options.toBundle());
+ mTarget.sendIntent(mContext, 0, fillIn,
+ null /* requiredPermission */, options.toBundle(),
+ null /* executor */, null /* onFinished*/);
} catch (SendIntentException ignored) {
}
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 47a79a3c4051..ff8a69de35bc 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -5053,8 +5053,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
try {
final BroadcastOptions options = BroadcastOptions.makeBasic();
options.setPendingIntentBackgroundActivityLaunchAllowed(false);
- target.sendIntent(mContext, 0 /* code */, intent, null /* onFinished */,
- null /* handler */, null /* requiredPermission */, options.toBundle());
+ target.sendIntent(mContext, 0 /* code */, intent,
+ null /* requiredPermission */, options.toBundle(),
+ null /* executor */, null /* onFinished*/);
} catch (IntentSender.SendIntentException ignored) {
}
}
@@ -5447,8 +5448,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
try {
final BroadcastOptions options = BroadcastOptions.makeBasic();
options.setPendingIntentBackgroundActivityLaunchAllowed(false);
- target.sendIntent(context, 0, fillIn, null /* onFinished */,
- null /* handler */, null /* requiredPermission */, options.toBundle());
+ target.sendIntent(context, 0, fillIn,
+ null /* requiredPermission */, options.toBundle(),
+ null /* executor */, null /* onFinished*/);
} catch (IntentSender.SendIntentException ignored) {
}
}
@@ -5496,8 +5498,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
try {
final BroadcastOptions options = BroadcastOptions.makeBasic();
options.setPendingIntentBackgroundActivityLaunchAllowed(false);
- target.sendIntent(context, 0, fillIn, null /* onFinished */,
- null /* handler */, null /* requiredPermission */, options.toBundle());
+ target.sendIntent(context, 0, fillIn,
+ null /* requiredPermission */, options.toBundle(),
+ null /* executor */, null /* onFinished*/);
} catch (IntentSender.SendIntentException ignored) {
}
}
@@ -5533,8 +5536,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
try {
final BroadcastOptions options = BroadcastOptions.makeBasic();
options.setPendingIntentBackgroundActivityLaunchAllowed(false);
- target.sendIntent(context, 0, intent, null /* onFinished */,
- null /* handler */, null /* requiredPermission */, options.toBundle());
+ target.sendIntent(context, 0, intent,
+ null /* requiredPermission */, options.toBundle(),
+ null /* executor */, null /* onFinished*/);
} catch (IntentSender.SendIntentException ignored) {
}
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 2e63cdbf1823..07c8ee75f932 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -186,7 +186,6 @@ import com.android.internal.pm.pkg.component.ParsedInstrumentation;
import com.android.internal.pm.pkg.component.ParsedMainComponent;
import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
import com.android.internal.telephony.CarrierAppUtils;
-import com.android.internal.telephony.TelephonyPermissions;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.ConcurrentUtils;
@@ -4493,7 +4492,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
void setSystemAppHiddenUntilInstalled(@NonNull Computer snapshot, String packageName,
boolean hidden) {
final int callingUid = Binder.getCallingUid();
- final boolean calledFromSystemOrPhone = TelephonyPermissions.isSystemOrPhone(callingUid);
+ final boolean calledFromSystemOrPhone = isSystemOrPhone(callingUid);
if (!calledFromSystemOrPhone) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.SUSPEND_APPS,
"setSystemAppHiddenUntilInstalled");
@@ -4518,8 +4517,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
boolean setSystemAppInstallState(@NonNull Computer snapshot, String packageName,
boolean installed, int userId) {
final int callingUid = Binder.getCallingUid();
- final boolean calledFromSystemOrPhone = callingUid == Process.PHONE_UID
- || callingUid == Process.SYSTEM_UID;
+ final boolean calledFromSystemOrPhone = isSystemOrPhone(callingUid);
if (!calledFromSystemOrPhone) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.SUSPEND_APPS,
"setSystemAppHiddenUntilInstalled");
@@ -5034,8 +5032,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService
final BroadcastOptions options = BroadcastOptions.makeBasic();
options.setPendingIntentBackgroundActivityLaunchAllowed(false);
pi.sendIntent(null, success ? 1 : 0, null /* intent */,
- null /* onFinished*/, null /* handler */,
- null /* requiredPermission */, options.toBundle());
+ null /* requiredPermission */, options.toBundle(),
+ null /* executor */, null /* onFinished*/);
} catch (SendIntentException e) {
Slog.w(TAG, e);
}
@@ -8123,4 +8121,9 @@ public class PackageManagerService implements PackageSender, TestUtilityService
PackageManager.VERSION_CODE_HIGHEST, UserHandle.USER_SYSTEM,
PackageManager.DELETE_ALL_USERS, true /*removedBySystem*/);
}
+
+ private static boolean isSystemOrPhone(int uid) {
+ return UserHandle.isSameApp(uid, Process.SYSTEM_UID)
+ || UserHandle.isSameApp(uid, Process.PHONE_UID);
+ }
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 924b36cef79a..c3cac2032a91 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -1419,10 +1419,23 @@ public class PackageManagerServiceUtils {
/**
* Check and throw if the given before/after packages would be considered a
- * downgrade.
+ * downgrade with {@link PackageSetting}.
*/
- public static void checkDowngrade(AndroidPackage before, PackageInfoLite after)
- throws PackageManagerException {
+ public static void checkDowngrade(@NonNull PackageSetting before,
+ @NonNull PackageInfoLite after) throws PackageManagerException {
+ if (after.getLongVersionCode() < before.getVersionCode()) {
+ throw new PackageManagerException(INSTALL_FAILED_VERSION_DOWNGRADE,
+ "Update version code " + after.versionCode + " is older than current "
+ + before.getVersionCode());
+ }
+ }
+
+ /**
+ * Check and throw if the given before/after packages would be considered a
+ * downgrade with {@link AndroidPackage}.
+ */
+ public static void checkDowngrade(@NonNull AndroidPackage before,
+ @NonNull PackageInfoLite after) throws PackageManagerException {
if (after.getLongVersionCode() < before.getLongVersionCode()) {
throw new PackageManagerException(INSTALL_FAILED_VERSION_DOWNGRADE,
"Update version code " + after.versionCode + " is older than current "
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 7870b1735af4..82df527edcc3 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -97,6 +97,7 @@ public class PackageSetting extends SettingBase implements PackageStateInternal
FORCE_QUERYABLE_OVERRIDE,
SCANNED_AS_STOPPED_SYSTEM_APP,
PENDING_RESTORE,
+ DEBUGGABLE,
})
public @interface Flags {
}
@@ -105,6 +106,7 @@ public class PackageSetting extends SettingBase implements PackageStateInternal
private static final int FORCE_QUERYABLE_OVERRIDE = 1 << 2;
private static final int SCANNED_AS_STOPPED_SYSTEM_APP = 1 << 3;
private static final int PENDING_RESTORE = 1 << 4;
+ private static final int DEBUGGABLE = 1 << 5;
}
private int mBooleans;
@@ -562,6 +564,20 @@ public class PackageSetting extends SettingBase implements PackageStateInternal
return getBoolean(Booleans.PENDING_RESTORE);
}
+ /**
+ * @see PackageState#isDebuggable
+ */
+ public PackageSetting setDebuggable(boolean value) {
+ setBoolean(Booleans.DEBUGGABLE, value);
+ onChanged();
+ return this;
+ }
+
+ @Override
+ public boolean isDebuggable() {
+ return getBoolean(Booleans.DEBUGGABLE);
+ }
+
@Override
public String toString() {
return "PackageSetting{"
diff --git a/services/core/java/com/android/server/pm/ScanPackageUtils.java b/services/core/java/com/android/server/pm/ScanPackageUtils.java
index 9ab6016f3d57..d8ce38e0cd2c 100644
--- a/services/core/java/com/android/server/pm/ScanPackageUtils.java
+++ b/services/core/java/com/android/server/pm/ScanPackageUtils.java
@@ -437,6 +437,9 @@ final class ScanPackageUtils {
pkgSetting.setIsOrphaned(true);
}
+ // update debuggable to packageSetting
+ pkgSetting.setDebuggable(parsedPackage.isDebuggable());
+
// Take care of first install / last update times.
final long scanFileTime = getLastModifiedTime(parsedPackage);
final long existingFirstInstallTime = userId == UserHandle.USER_ALL
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 39565526f33e..0d16b009d9a5 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -3255,6 +3255,9 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
if (pkg.isPendingRestore()) {
serializer.attributeBoolean(null, "pendingRestore", true);
}
+ if (pkg.isDebuggable()) {
+ serializer.attributeBoolean(null, "debuggable", true);
+ }
if (pkg.isLoading()) {
serializer.attributeBoolean(null, "isLoading", true);
}
@@ -3269,7 +3272,6 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
serializer.attributeInt(null, "appMetadataSource",
pkg.getAppMetadataSource());
-
writeUsesSdkLibLPw(serializer, pkg.getUsesSdkLibraries(),
pkg.getUsesSdkLibrariesVersionsMajor(), pkg.getUsesSdkLibrariesOptional());
@@ -4059,6 +4061,7 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
long versionCode = 0;
boolean installedForceQueryable = false;
boolean isPendingRestore = false;
+ boolean isDebuggable = false;
float loadingProgress = 0;
long loadingCompletedTime = 0;
UUID domainSetId;
@@ -4085,6 +4088,7 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
updateAvailable = parser.getAttributeBoolean(null, "updateAvailable", false);
installedForceQueryable = parser.getAttributeBoolean(null, "forceQueryable", false);
isPendingRestore = parser.getAttributeBoolean(null, "pendingRestore", false);
+ isDebuggable = parser.getAttributeBoolean(null, "debuggable", false);
loadingProgress = parser.getAttributeFloat(null, "loadingProgress", 0);
loadingCompletedTime = parser.getAttributeLongHex(null, "loadingCompletedTime", 0);
@@ -4259,6 +4263,7 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
.setUpdateAvailable(updateAvailable)
.setForceQueryableOverride(installedForceQueryable)
.setPendingRestore(isPendingRestore)
+ .setDebuggable(isDebuggable)
.setLoadingProgress(loadingProgress)
.setLoadingCompletedTime(loadingCompletedTime)
.setAppMetadataFilePath(appMetadataFilePath)
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 1cd77ffcedaa..021f7aa9c215 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -3443,6 +3443,14 @@ public class ShortcutService extends IShortcutService.Stub {
}
@Override
+ public void removeShortcutChangeCallback(
+ @NonNull LauncherApps.ShortcutChangeCallback callback) {
+ synchronized (mServiceLock) {
+ mShortcutChangeCallbacks.remove(Objects.requireNonNull(callback));
+ }
+ }
+
+ @Override
public int getShortcutIconResId(int launcherUserId, @NonNull String callingPackage,
@NonNull String packageName, @NonNull String shortcutId, int userId) {
Objects.requireNonNull(callingPackage, "callingPackage");
@@ -4482,8 +4490,9 @@ public class ShortcutService extends IShortcutService.Stub {
ActivityOptions options = ActivityOptions.makeBasic()
.setPendingIntentBackgroundActivityStartMode(
MODE_BACKGROUND_ACTIVITY_START_DENIED);
- intentSender.sendIntent(mContext, /* code= */ 0, extras,
- /* onFinished=*/ null, /* handler= */ null, null, options.toBundle());
+ intentSender.sendIntent(mContext, 0 /* code */, extras,
+ null /* requiredPermission */, options.toBundle(),
+ null /* executor */, null /* onFinished*/);
} catch (SendIntentException e) {
Slog.w(TAG, "sendIntent failed().", e);
}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index b9a9d64fc50e..dde9943ccd7b 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1176,6 +1176,30 @@ public class UserManagerService extends IUserManager.Stub {
}
}
+ /** Marks the user as slated for deletion during boot if necessary. **/
+ @GuardedBy("mUsersLock")
+ private void markUserForRemovalIfNecessaryLU(UserInfo ui) {
+ if (!ui.isEphemeral()) {
+ // User should be ephemeral to be marked for removal.
+ return;
+ }
+ if (ui.preCreated) {
+ // Avoid marking pre-created users for removal.
+ return;
+ }
+ if (ui.lastLoggedInTime == 0 && ui.isGuest() && Resources.getSystem().getBoolean(
+ com.android.internal.R.bool.config_guestUserAutoCreated)) {
+ // Avoid marking auto-created but not-yet-logged-in guest user for removal. Because a
+ // new one will be created anyway, and this one doesn't have any personal data in it yet
+ // due to not being logged in.
+ return;
+ }
+ // Mark the user for removal.
+ addRemovingUserIdLocked(ui.id);
+ ui.partial = true;
+ ui.flags |= UserInfo.FLAG_DISABLED;
+ }
+
/* Prunes out any partially created or partially removed users. */
private void cleanupPartialUsers() {
ArrayList<UserInfo> partials = new ArrayList<>();
@@ -1901,6 +1925,7 @@ public class UserManagerService extends IUserManager.Stub {
Slog.i(LOG_TAG, "Quiet mode is already " + enableQuietMode);
return;
}
+ UserManager.invalidateQuietModeEnabledCache();
profile.flags ^= UserInfo.FLAG_QUIET_MODE;
profileUserData = getUserDataLU(profile.id);
}
@@ -4340,13 +4365,7 @@ public class UserManagerService extends IUserManager.Stub {
|| mNextSerialNumber <= userData.info.id) {
mNextSerialNumber = userData.info.id + 1;
}
- if (userData.info.isEphemeral() && !userData.info.preCreated
- && userData.info.id != UserHandle.USER_SYSTEM) {
- // Mark ephemeral user as slated for deletion.
- addRemovingUserIdLocked(userData.info.id);
- userData.info.partial = true;
- userData.info.flags |= UserInfo.FLAG_DISABLED;
- }
+ markUserForRemovalIfNecessaryLU(userData.info);
}
}
} else if (name.equals(TAG_GUEST_RESTRICTIONS)) {
diff --git a/services/core/java/com/android/server/pm/pkg/PackageState.java b/services/core/java/com/android/server/pm/pkg/PackageState.java
index e0ee199a343d..58761886ecb9 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageState.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageState.java
@@ -274,6 +274,14 @@ public interface PackageState {
boolean isPendingRestore();
/**
+ * @see ApplicationInfo#FLAG_DEBUGGABLE
+ * @see R.styleable#AndroidManifestApplication_debuggable
+ * @see AndroidPackage#isDebuggable
+ * @hide
+ */
+ boolean isDebuggable();
+
+ /**
* Retrieves the shared user app ID. Note that the actual shared user data is not available here
* and must be queried separately.
*
diff --git a/services/core/java/com/android/server/policy/ModifierShortcutManager.java b/services/core/java/com/android/server/policy/ModifierShortcutManager.java
index 3a79d0df4819..fde23b726572 100644
--- a/services/core/java/com/android/server/policy/ModifierShortcutManager.java
+++ b/services/core/java/com/android/server/policy/ModifierShortcutManager.java
@@ -22,8 +22,10 @@ import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.res.XmlResourceParser;
+import android.graphics.drawable.Icon;
import android.hardware.input.InputManager;
import android.os.Handler;
import android.os.RemoteException;
@@ -36,7 +38,11 @@ import android.util.SparseArray;
import android.view.InputDevice;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
+import android.view.KeyboardShortcutGroup;
+import android.view.KeyboardShortcutInfo;
+import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.policy.IShortcutService;
import com.android.internal.util.XmlUtils;
import com.android.server.input.KeyboardMetricsCollector;
@@ -46,7 +52,9 @@ import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
/**
@@ -183,8 +191,12 @@ public class ModifierShortcutManager {
String rolePackage = mRoleManager.getDefaultApplication(role);
if (rolePackage != null) {
intent = mPackageManager.getLaunchIntentForPackage(rolePackage);
- intent.putExtra(EXTRA_ROLE, role);
- mRoleIntents.put(role, intent);
+ if (intent != null) {
+ intent.putExtra(EXTRA_ROLE, role);
+ mRoleIntents.put(role, intent);
+ } else {
+ Log.w(TAG, "No launch intent for role " + role);
+ }
} else {
Log.w(TAG, "No default application for role " + role);
}
@@ -198,8 +210,7 @@ public class ModifierShortcutManager {
private void loadShortcuts() {
try {
- XmlResourceParser parser = mContext.getResources().getXml(
- com.android.internal.R.xml.bookmarks);
+ XmlResourceParser parser = mContext.getResources().getXml(R.xml.bookmarks);
XmlUtils.beginDocument(parser, TAG_BOOKMARKS);
while (true) {
@@ -270,6 +281,9 @@ public class ModifierShortcutManager {
continue;
}
intent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, categoryName);
+ if (intent == null) {
+ Log.w(TAG, "Null selector intent for " + categoryName);
+ }
} else if (roleName != null) {
// We can't resolve the role at the time of this file being parsed as the
// device hasn't finished booting, so we will look it up lazily.
@@ -466,4 +480,131 @@ public class ModifierShortcutManager {
return false;
}
+
+ /**
+ * @param deviceId The input device id of the input device that will handle the shortcuts.
+ *
+ * @return a {@link KeyboardShortcutGroup} containing the application launch keyboard
+ * shortcuts parsed at boot time from {@code bookmarks.xml}.
+ */
+ public KeyboardShortcutGroup getApplicationLaunchKeyboardShortcuts(int deviceId) {
+ List<KeyboardShortcutInfo> shortcuts = new ArrayList();
+ for (int i = 0; i < mIntentShortcuts.size(); i++) {
+ KeyboardShortcutInfo info = shortcutInfoFromIntent(
+ (char) (mIntentShortcuts.keyAt(i)), mIntentShortcuts.valueAt(i), false);
+ if (info != null) {
+ shortcuts.add(info);
+ }
+ }
+
+ for (int i = 0; i < mShiftShortcuts.size(); i++) {
+ KeyboardShortcutInfo info = shortcutInfoFromIntent(
+ (char) (mShiftShortcuts.keyAt(i)), mShiftShortcuts.valueAt(i), true);
+ if (info != null) {
+ shortcuts.add(info);
+ }
+ }
+
+ for (int i = 0; i < mRoleShortcuts.size(); i++) {
+ String role = mRoleShortcuts.valueAt(i);
+ KeyboardShortcutInfo info = shortcutInfoFromIntent(
+ (char) (mRoleShortcuts.keyAt(i)), getRoleLaunchIntent(role), false);
+ if (info != null) {
+ shortcuts.add(info);
+ }
+ }
+
+ for (int i = 0; i < mShiftRoleShortcuts.size(); i++) {
+ String role = mShiftRoleShortcuts.valueAt(i);
+ KeyboardShortcutInfo info = shortcutInfoFromIntent(
+ (char) (mShiftRoleShortcuts.keyAt(i)), getRoleLaunchIntent(role), true);
+ if (info != null) {
+ shortcuts.add(info);
+ }
+ }
+
+ return new KeyboardShortcutGroup(
+ mContext.getString(R.string.keyboard_shortcut_group_applications),
+ shortcuts);
+ }
+
+ /**
+ * Given an intent to launch an application and the character and shift state that should
+ * trigger it, return a suitable {@link KeyboardShortcutInfo} that contains the label and
+ * icon for the target application.
+ *
+ * @param baseChar the character that triggers the shortcut
+ * @param intent the application launch intent
+ * @param shift whether the shift key is required to be presed.
+ */
+ @VisibleForTesting
+ KeyboardShortcutInfo shortcutInfoFromIntent(char baseChar, Intent intent, boolean shift) {
+ if (intent == null) {
+ return null;
+ }
+
+ CharSequence label;
+ Icon icon;
+ ActivityInfo resolvedActivity = intent.resolveActivityInfo(
+ mPackageManager, PackageManager.MATCH_DEFAULT_ONLY);
+ if (resolvedActivity == null) {
+ return null;
+ }
+ boolean isResolver = com.android.internal.app.ResolverActivity.class.getName().equals(
+ resolvedActivity.name);
+ if (isResolver) {
+ label = getIntentCategoryLabel(mContext,
+ intent.getSelector().getCategories().iterator().next());
+ if (label == null) {
+ return null;
+ }
+ icon = Icon.createWithResource(mContext, R.drawable.sym_def_app_icon);
+
+ } else {
+ label = resolvedActivity.loadLabel(mPackageManager);
+ icon = Icon.createWithResource(
+ resolvedActivity.packageName, resolvedActivity.getIconResource());
+ }
+ int modifiers = KeyEvent.META_META_ON;
+ if (shift) {
+ modifiers |= KeyEvent.META_SHIFT_ON;
+ }
+ return new KeyboardShortcutInfo(label, icon, baseChar, modifiers);
+ }
+
+ @VisibleForTesting
+ static String getIntentCategoryLabel(Context context, CharSequence category) {
+ int resid;
+ switch (category.toString()) {
+ case Intent.CATEGORY_APP_BROWSER:
+ resid = R.string.keyboard_shortcut_group_applications_browser;
+ break;
+ case Intent.CATEGORY_APP_CONTACTS:
+ resid = R.string.keyboard_shortcut_group_applications_contacts;
+ break;
+ case Intent.CATEGORY_APP_EMAIL:
+ resid = R.string.keyboard_shortcut_group_applications_email;
+ break;
+ case Intent.CATEGORY_APP_CALENDAR:
+ resid = R.string.keyboard_shortcut_group_applications_calendar;
+ break;
+ case Intent.CATEGORY_APP_MAPS:
+ resid = R.string.keyboard_shortcut_group_applications_maps;
+ break;
+ case Intent.CATEGORY_APP_MUSIC:
+ resid = R.string.keyboard_shortcut_group_applications_music;
+ break;
+ case Intent.CATEGORY_APP_MESSAGING:
+ resid = R.string.keyboard_shortcut_group_applications_sms;
+ break;
+ case Intent.CATEGORY_APP_CALCULATOR:
+ resid = R.string.keyboard_shortcut_group_applications_calculator;
+ break;
+ default:
+ Log.e(TAG, ("No label for app category " + category));
+ return null;
+ }
+ return context.getString(resid);
+ };
+
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index c9ba683a698a..8dc97566d1d2 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -189,6 +189,7 @@ import android.view.InputDevice;
import android.view.KeyCharacterMap;
import android.view.KeyCharacterMap.FallbackAction;
import android.view.KeyEvent;
+import android.view.KeyboardShortcutGroup;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
import android.view.WindowManager;
@@ -3321,6 +3322,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {
eventToLog).sendToTarget();
}
+ @Override
+ public KeyboardShortcutGroup getApplicationLaunchKeyboardShortcuts(int deviceId) {
+ return mModifierShortcutManager.getApplicationLaunchKeyboardShortcuts(deviceId);
+ }
+
// TODO(b/117479243): handle it in InputPolicy
// TODO (b/283241997): Add the remaining keyboard shortcut logging after refactoring
/** {@inheritDoc} */
@@ -3568,24 +3574,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
Slog.wtf(TAG, "KEYCODE_VOICE_ASSIST should be handled in"
+ " interceptKeyBeforeQueueing");
return true;
- case KeyEvent.KEYCODE_VIDEO_APP_1:
- case KeyEvent.KEYCODE_VIDEO_APP_2:
- case KeyEvent.KEYCODE_VIDEO_APP_3:
- case KeyEvent.KEYCODE_VIDEO_APP_4:
- case KeyEvent.KEYCODE_VIDEO_APP_5:
- case KeyEvent.KEYCODE_VIDEO_APP_6:
- case KeyEvent.KEYCODE_VIDEO_APP_7:
- case KeyEvent.KEYCODE_VIDEO_APP_8:
- case KeyEvent.KEYCODE_FEATURED_APP_1:
- case KeyEvent.KEYCODE_FEATURED_APP_2:
- case KeyEvent.KEYCODE_FEATURED_APP_3:
- case KeyEvent.KEYCODE_FEATURED_APP_4:
- case KeyEvent.KEYCODE_DEMO_APP_1:
- case KeyEvent.KEYCODE_DEMO_APP_2:
- case KeyEvent.KEYCODE_DEMO_APP_3:
- case KeyEvent.KEYCODE_DEMO_APP_4:
- Slog.wtf(TAG, "KEYCODE_APP_X should be handled in interceptKeyBeforeQueueing");
- return true;
case KeyEvent.KEYCODE_BRIGHTNESS_UP:
case KeyEvent.KEYCODE_BRIGHTNESS_DOWN:
if (down) {
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index 9ca4e273ac39..6c05d70f8513 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -82,6 +82,7 @@ import android.util.proto.ProtoOutputStream;
import android.view.Display;
import android.view.IDisplayFoldListener;
import android.view.KeyEvent;
+import android.view.KeyboardShortcutGroup;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.view.WindowManagerPolicyConstants;
@@ -698,6 +699,15 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags);
/**
+ * Return the set of applicaition launch keyboard shortcuts the system supports.
+ *
+ * @param deviceId The id of the {@link InputDevice} that will trigger the shortcut.
+ *
+ * @return {@link KeyboardShortcutGroup} containing the shortcuts.
+ */
+ KeyboardShortcutGroup getApplicationLaunchKeyboardShortcuts(int deviceId);
+
+ /**
* Called from the input reader thread before a motion is enqueued when the device is in a
* non-interactive state.
*
diff --git a/services/core/java/com/android/server/power/LowPowerStandbyController.java b/services/core/java/com/android/server/power/LowPowerStandbyController.java
index fa94b43b6d0e..421471e2eeec 100644
--- a/services/core/java/com/android/server/power/LowPowerStandbyController.java
+++ b/services/core/java/com/android/server/power/LowPowerStandbyController.java
@@ -1380,10 +1380,7 @@ public class LowPowerStandbyController {
Slog.d(TAG, "notifyStandbyPortsChanged");
}
- final Intent intent = new Intent(PowerManager.ACTION_LOW_POWER_STANDBY_PORTS_CHANGED);
- intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
- mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
- Manifest.permission.MANAGE_LOW_POWER_STANDBY);
+ sendExplicitBroadcast(PowerManager.ACTION_LOW_POWER_STANDBY_PORTS_CHANGED);
}
/**
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index f85b8cc9c1bb..aa5f5a24f179 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -206,7 +206,6 @@ public class Notifier {
mPolicy = policy;
mFaceDownDetector = faceDownDetector;
mScreenUndimDetector = screenUndimDetector;
- mWakefulnessSessionObserver = new WakefulnessSessionObserver(mContext, null);
mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
mInputMethodManagerInternal = LocalServices.getService(InputMethodManagerInternal.class);
@@ -214,6 +213,7 @@ public class Notifier {
mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
mTrustManager = mContext.getSystemService(TrustManager.class);
mVibrator = mContext.getSystemService(Vibrator.class);
+ mWakefulnessSessionObserver = new WakefulnessSessionObserver(mContext, null);
mHandler = new NotifierHandler(looper);
mBackgroundExecutor = backgroundExecutor;
@@ -813,6 +813,8 @@ public class Notifier {
if (DEBUG) {
Slog.d(TAG, "onScreenPolicyUpdate: newPolicy=" + newPolicy);
}
+ mWakefulnessSessionObserver.onScreenPolicyUpdate(
+ SystemClock.uptimeMillis(), displayGroupId, newPolicy);
synchronized (mLock) {
Message msg = mHandler.obtainMessage(MSG_SCREEN_POLICY);
diff --git a/services/core/java/com/android/server/power/WakefulnessSessionObserver.java b/services/core/java/com/android/server/power/WakefulnessSessionObserver.java
index d57cd5df41db..3546565480ad 100644
--- a/services/core/java/com/android/server/power/WakefulnessSessionObserver.java
+++ b/services/core/java/com/android/server/power/WakefulnessSessionObserver.java
@@ -16,8 +16,11 @@
package com.android.server.power;
+import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_BRIGHT;
+import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_DIM;
import static android.os.PowerManager.USER_ACTIVITY_EVENT_OTHER;
import static android.os.PowerManagerInternal.isInteractive;
+import static android.view.Display.DEFAULT_DISPLAY;
import static com.android.server.power.PowerManagerService.DEFAULT_SCREEN_OFF_TIMEOUT;
import static com.android.server.power.ScreenTimeoutOverridePolicy.RELEASE_REASON_NON_INTERACTIVE;
@@ -34,6 +37,9 @@ import android.app.ActivityManager;
import android.app.SynchronousUserSwitchObserver;
import android.content.Context;
import android.database.ContentObserver;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayManagerInternal;
+import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
import android.os.Handler;
import android.os.PowerManager;
import android.os.PowerManagerInternal;
@@ -44,9 +50,13 @@ import android.provider.Settings;
import android.util.IndentingPrintWriter;
import android.util.SparseArray;
import android.view.Display;
+import android.view.DisplayAddress;
+import android.view.DisplayInfo;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.BackgroundThread;
import com.android.internal.util.FrameworkStatsLog;
+import com.android.server.LocalServices;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
@@ -117,9 +127,42 @@ public class WakefulnessSessionObserver {
@Retention(RetentionPolicy.SOURCE)
private @interface OverrideOutcome {}
- private static final int DEFAULT_USER_ACTIVITY = USER_ACTIVITY_EVENT_OTHER;
- private static final long TIMEOUT_USER_INITIATED_REVERT_THRESHOLD_MILLIS = 5000L;
+ private static final int POLICY_REASON_UNKNOWN = FrameworkStatsLog
+ .SCREEN_DIM_REPORTED__POLICY_REASON__UNKNOWN;
+ @VisibleForTesting
+ protected static final int POLICY_REASON_OFF_TIMEOUT = FrameworkStatsLog
+ .SCREEN_DIM_REPORTED__POLICY_REASON__OFF_TIMEOUT;
+ @VisibleForTesting
+ protected static final int POLICY_REASON_OFF_POWER_BUTTON = FrameworkStatsLog
+ .SCREEN_DIM_REPORTED__POLICY_REASON__OFF_POWER_BUTTON;
+ @VisibleForTesting
+ protected static final int POLICY_REASON_BRIGHT_UNDIM = FrameworkStatsLog
+ .SCREEN_DIM_REPORTED__POLICY_REASON__BRIGHT_UNDIM;
+ @VisibleForTesting
+ protected static final int POLICY_REASON_BRIGHT_INITIATED_REVERT = FrameworkStatsLog
+ .SCREEN_DIM_REPORTED__POLICY_REASON__BRIGHT_INITIATED_REVERT;
+
+ /**
+ * Policy Reason
+ * {@link android.os.statsd.power.ScreenDimReported.PolicyReason}.
+ */
+ @IntDef(prefix = {"POLICY_REASON_"}, value = {
+ POLICY_REASON_UNKNOWN,
+ POLICY_REASON_OFF_TIMEOUT,
+ POLICY_REASON_OFF_POWER_BUTTON,
+ POLICY_REASON_BRIGHT_UNDIM,
+ POLICY_REASON_BRIGHT_INITIATED_REVERT
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ private @interface PolicyReason {}
+
+ @VisibleForTesting protected static final int DEFAULT_USER_ACTIVITY = USER_ACTIVITY_EVENT_OTHER;
+ private static final long USER_INITIATED_REVERT_THRESHOLD_MILLIS = 5000L;
private static final long SEND_OVERRIDE_TIMEOUT_LOG_THRESHOLD_MILLIS = 1000L;
+ @VisibleForTesting
+ protected static final long SCREEN_POLICY_DIM_POWER_OFF_BRIGHT_THRESHOLD_MILLIS = 500L;
+
+ @VisibleForTesting protected static final Object HANDLER_TOKEN = new Object();
private Context mContext;
private int mScreenOffTimeoutMs;
@@ -130,17 +173,24 @@ public class WakefulnessSessionObserver {
protected WakefulnessSessionFrameworkStatsLogger mWakefulnessSessionFrameworkStatsLogger;
private final Clock mClock;
private final Object mLock = new Object();
+ private final Handler mHandler;
- public WakefulnessSessionObserver(Context context, Injector injector) {
+ private DisplayManagerInternal mDisplayManagerInternal;
+ private int mPhysicalDisplayPortIdForDefaultDisplay;
+
+ public WakefulnessSessionObserver(
+ Context context, Injector injector) {
if (injector == null) {
injector = new Injector();
}
mContext = context;
+ mDisplayManagerInternal = injector.getDisplayManagerInternal();
mWakefulnessSessionFrameworkStatsLogger = injector
.getWakefulnessSessionFrameworkStatsLogger();
mClock = injector.getClock();
- updateSettingScreenOffTimeout(context);
+ mHandler = injector.getHandler();
+ updateSettingScreenOffTimeout(mContext);
try {
final UserSwitchObserver observer = new UserSwitchObserver();
@@ -164,6 +214,31 @@ public class WakefulnessSessionObserver {
},
UserHandle.USER_ALL);
+ mPhysicalDisplayPortIdForDefaultDisplay = getPhysicalDisplayPortId(DEFAULT_DISPLAY);
+ DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
+ if (displayManager != null) {
+ displayManager.registerDisplayListener(
+ new DisplayManager.DisplayListener() {
+ @Override
+ public void onDisplayChanged(int displayId) {
+ if (displayId == DEFAULT_DISPLAY) {
+ mPhysicalDisplayPortIdForDefaultDisplay = getPhysicalDisplayPortId(
+ DEFAULT_DISPLAY);
+ }
+ }
+
+ @Override
+ public void onDisplayAdded(int i) {
+ }
+
+ @Override
+ public void onDisplayRemoved(int i) {
+ }
+ },
+ mHandler,
+ DisplayManager.EVENT_FLAG_DISPLAY_CHANGED);
+ }
+
mPowerGroups.append(
Display.DEFAULT_DISPLAY_GROUP,
new WakefulnessSessionPowerGroup(Display.DEFAULT_DISPLAY_GROUP));
@@ -186,6 +261,20 @@ public class WakefulnessSessionObserver {
}
/**
+ * Track the screen policy
+ *
+ * @param eventTime policy changing time, in uptime millis.
+ * @param powerGroupId Power Group Id for this screen policy
+ * @param newPolicy Screen Policy defined in {@link DisplayPowerRequest}
+ */
+ public void onScreenPolicyUpdate(long eventTime, int powerGroupId, int newPolicy) {
+ if (!mPowerGroups.contains(powerGroupId)) {
+ mPowerGroups.append(powerGroupId, new WakefulnessSessionPowerGroup(powerGroupId));
+ }
+ mPowerGroups.get(powerGroupId).onScreenPolicyUpdate(eventTime, newPolicy);
+ }
+
+ /**
* Track the system wakefulness
*
* @param powerGroupId Power Group Id for this wakefulness changes
@@ -267,6 +356,14 @@ public class WakefulnessSessionObserver {
}
}
+ private int getPhysicalDisplayPortId(int displayId) {
+ if (mDisplayManagerInternal == null) {
+ return -1;
+ }
+ DisplayInfo display = mDisplayManagerInternal.getDisplayInfo(displayId);
+ return ((DisplayAddress.Physical) display.address).getPort();
+ }
+
private int getScreenOffTimeout() {
synchronized (mLock) {
return mScreenOffTimeoutMs;
@@ -277,10 +374,9 @@ public class WakefulnessSessionObserver {
@VisibleForTesting
protected class WakefulnessSessionPowerGroup {
private static final long TIMEOUT_OFF_RESET_TIMESTAMP = -1;
-
private int mPowerGroupId;
private int mCurrentWakefulness;
- private boolean mIsInteractive = false;
+ @VisibleForTesting protected boolean mIsInteractive = false;
// state on start timestamp: will be used in state off to calculate the duration of state on
private long mInteractiveStateOnStartTimestamp;
@VisibleForTesting
@@ -295,6 +391,17 @@ public class WakefulnessSessionObserver {
private int mTimeoutOverrideWakeLockCounter = 0;
// The timestamp when Override Timeout is set to false
private @ScreenTimeoutOverridePolicy.ReleaseReason int mTimeoutOverrideReleaseReason;
+ // The timestamp when current screen policy is set
+ private long mCurrentScreenPolicyTimestamp;
+ // current screen policy
+ private int mCurrentScreenPolicy;
+ // The screen policy before the current one
+ private int mPrevScreenPolicy;
+ // The previous screen policy duration
+ private int mPrevScreenPolicyDurationMs;
+ // The past dim duration
+ @VisibleForTesting protected int mPastDimDurationMs;
+ private long mInteractiveOffTimestamp;
// The timestamp when state off by timeout occurs
// will set TIMEOUT_OFF_RESET_TIMESTAMP if state on or state off by power button
private long mTimeoutOffTimestamp;
@@ -307,6 +414,10 @@ public class WakefulnessSessionObserver {
mPrevUserActivityEvent = DEFAULT_USER_ACTIVITY;
mPrevUserActivityTimestamp = -1;
mPowerGroupId = powerGroupId;
+ mCurrentScreenPolicy = mPrevScreenPolicy = POLICY_BRIGHT;
+ mCurrentScreenPolicyTimestamp = 0;
+ mPrevScreenPolicyDurationMs = 0;
+ mPastDimDurationMs = 0;
}
public void notifyUserActivity(long eventTime, @PowerManager.UserActivityEvent int event) {
@@ -320,6 +431,21 @@ public class WakefulnessSessionObserver {
mCurrentUserActivityTimestamp = eventTime;
}
+ public void onScreenPolicyUpdate(long eventTime, int newPolicy) {
+ if (newPolicy == mCurrentScreenPolicy) {
+ return;
+ }
+
+ if (newPolicy == POLICY_BRIGHT) {
+ checkAndLogDimIfQualified(POLICY_REASON_BRIGHT_UNDIM, eventTime);
+ }
+
+ mPrevScreenPolicy = mCurrentScreenPolicy;
+ mCurrentScreenPolicy = newPolicy;
+ mPrevScreenPolicyDurationMs = (int) (eventTime - mCurrentScreenPolicyTimestamp);
+ mCurrentScreenPolicyTimestamp = eventTime;
+ }
+
public void onWakefulnessChangeStarted(int wakefulness, int changeReason, long eventTime) {
mCurrentWakefulness = wakefulness;
if (mIsInteractive == isInteractive(wakefulness)) {
@@ -331,10 +457,10 @@ public class WakefulnessSessionObserver {
mInteractiveStateOnStartTimestamp = eventTime;
// Log the outcome of screen timeout override (USER INITIATED REVERT),
- // when user initiates to revert the screen off state in a short period.
+ // when user initiates to revert the off state in a short period.
if (mTimeoutOffTimestamp != TIMEOUT_OFF_RESET_TIMESTAMP) {
- long offToOnDurationMs = eventTime - mTimeoutOffTimestamp;
- if (offToOnDurationMs < TIMEOUT_USER_INITIATED_REVERT_THRESHOLD_MILLIS) {
+ long timeoutOffToOnDurationMs = eventTime - mTimeoutOffTimestamp;
+ if (timeoutOffToOnDurationMs < USER_INITIATED_REVERT_THRESHOLD_MILLIS) {
mWakefulnessSessionFrameworkStatsLogger.logTimeoutOverrideEvent(
mPowerGroupId,
OVERRIDE_OUTCOME_TIMEOUT_USER_INITIATED_REVERT,
@@ -344,11 +470,15 @@ public class WakefulnessSessionObserver {
}
mTimeoutOffTimestamp = TIMEOUT_OFF_RESET_TIMESTAMP;
}
+
+ checkAndLogDimIfQualified(POLICY_REASON_BRIGHT_INITIATED_REVERT, eventTime);
+
} else {
int lastUserActivity = mCurrentUserActivityEvent;
long lastUserActivityDurationMs = eventTime - mCurrentUserActivityTimestamp;
@OffReason int interactiveStateOffReason = OFF_REASON_UNKNOWN;
int reducedInteractiveStateOnDurationMs = 0;
+ mInteractiveOffTimestamp = eventTime;
if (changeReason == PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON) {
interactiveStateOffReason = OFF_REASON_POWER_BUTTON;
@@ -369,6 +499,9 @@ public class WakefulnessSessionObserver {
mSendOverrideTimeoutLogTimestamp = eventTime;
mTimeoutOverrideReleaseReason = RELEASE_REASON_UNKNOWN; // reset the reason
}
+
+ checkAndLogDimIfQualified(POLICY_REASON_OFF_POWER_BUTTON, eventTime);
+
} else if (changeReason == PowerManager.GO_TO_SLEEP_REASON_TIMEOUT) {
// Interactive Off reason is timeout
interactiveStateOffReason = OFF_REASON_TIMEOUT;
@@ -393,6 +526,8 @@ public class WakefulnessSessionObserver {
// state instantly
mTimeoutOffTimestamp = eventTime;
}
+
+ checkAndLogDimIfQualified(POLICY_REASON_OFF_TIMEOUT, eventTime);
}
long interactiveStateOnDurationMs =
@@ -462,6 +597,106 @@ public class WakefulnessSessionObserver {
}
}
+ private void checkAndLogDimIfQualified(
+ @PolicyReason int reasonToBeChecked, long eventTime) {
+ // Only log dim event when DEFAULT_DISPLAY
+ if (mPowerGroupId != DEFAULT_DISPLAY) {
+ return;
+ }
+
+ int dimDurationMs = 0;
+ int lastUserActivity = mCurrentUserActivityEvent;
+ int lastUserActivityDurationMs = (int) (eventTime - mCurrentUserActivityTimestamp);
+ switch (reasonToBeChecked) {
+ case POLICY_REASON_OFF_TIMEOUT: {
+ // The policy ordering:
+ // (1) --DIM--OFF/DOZE->| or (2) --DIM->| because OFF/DOZE hasn't been updated.
+ dimDurationMs = (int) (eventTime - mCurrentScreenPolicyTimestamp); //(1)--DIM->|
+ if (mPrevScreenPolicy == POLICY_DIM) { // for (2) --DIM--OFF/DOZE->|
+ dimDurationMs = mPrevScreenPolicyDurationMs;
+ }
+ mWakefulnessSessionFrameworkStatsLogger.logDimEvent(
+ mPhysicalDisplayPortIdForDefaultDisplay,
+ reasonToBeChecked,
+ lastUserActivity,
+ lastUserActivityDurationMs,
+ dimDurationMs,
+ mScreenOffTimeoutMs);
+ mPastDimDurationMs = dimDurationMs;
+ return;
+ }
+ case POLICY_REASON_OFF_POWER_BUTTON: {
+ // Power Off will be triggered by USER_ACTIVITY_EVENT_BUTTON
+ // The metric wants to record the previous activity before EVENT_BUTTON
+ lastUserActivity = mPrevUserActivityEvent;
+ lastUserActivityDurationMs = (int) (eventTime - mPrevUserActivityTimestamp);
+ // the policy ordering:
+ // (1) ---BRIGHT->| or (2) ---DIM->| because OFF/DOZE hasn't been updated
+ dimDurationMs = 0; // for (1) ---BRIGHT->| which doesn't have dim (no need log)
+ if (mCurrentScreenPolicy == POLICY_DIM) { // for (2) ---DIM->|
+ dimDurationMs = (int) (eventTime - mCurrentScreenPolicyTimestamp);
+ mWakefulnessSessionFrameworkStatsLogger.logDimEvent(
+ mPhysicalDisplayPortIdForDefaultDisplay,
+ reasonToBeChecked,
+ lastUserActivity,
+ lastUserActivityDurationMs,
+ dimDurationMs,
+ mScreenOffTimeoutMs);
+ mHandler.removeCallbacksAndMessages(HANDLER_TOKEN);
+ }
+
+ mPastDimDurationMs = dimDurationMs;
+ return;
+ }
+ case POLICY_REASON_BRIGHT_UNDIM: {
+ // Has checked the latest screen policy is POLICY_BRIGHT in onScreenPolicyUpdate
+ if (mCurrentScreenPolicy == POLICY_DIM) { // policy ordering: --DIM--BRIGHT->|
+ int savedDimDurationMs = (int) (eventTime - mCurrentScreenPolicyTimestamp);
+ int savedLastUserActivity = lastUserActivity;
+ int savedLastUserActivityDurationMs = lastUserActivityDurationMs;
+
+ // For the undim case --DIM--BRIGHT->|, it needs wait 500 ms to
+ // differentiate between "power button off" case, which is
+ // --DIM--BRIGHT(<500ms)--OFF/DOZE->|
+ // [Method] Wait 500 ms to see whether triggers power button off or not.
+ // [Reason] We got --DIM--BRIGHT->|. However, if BRIGHT is so short (<500ms)
+ // and follows OFF/DOZE, it represents power button off, not undim.
+ // It is normal to have a short BRIGHT for power button off because
+ // the system need to play an animation before off.
+ mHandler.postDelayed(() -> {
+ mWakefulnessSessionFrameworkStatsLogger.logDimEvent(
+ mPhysicalDisplayPortIdForDefaultDisplay,
+ reasonToBeChecked,
+ savedLastUserActivity,
+ savedLastUserActivityDurationMs,
+ savedDimDurationMs,
+ mScreenOffTimeoutMs);
+ mPastDimDurationMs = savedDimDurationMs;
+ }, HANDLER_TOKEN, SCREEN_POLICY_DIM_POWER_OFF_BRIGHT_THRESHOLD_MILLIS);
+ }
+ return;
+ }
+ case POLICY_REASON_BRIGHT_INITIATED_REVERT: {
+ // the dimDuration in BRIGHT_INITIATE_REVERT is for the dim duration before
+ // screen interactive off (mPastDimDurationMs)
+ long offToOnDurationMs = eventTime - mInteractiveOffTimestamp;
+ if (mPastDimDurationMs > 0
+ && offToOnDurationMs < USER_INITIATED_REVERT_THRESHOLD_MILLIS) {
+ mWakefulnessSessionFrameworkStatsLogger.logDimEvent(
+ mPhysicalDisplayPortIdForDefaultDisplay,
+ reasonToBeChecked,
+ lastUserActivity,
+ lastUserActivityDurationMs,
+ mPastDimDurationMs,
+ mScreenOffTimeoutMs);
+ }
+ return;
+ }
+ default:
+ return;
+ }
+ }
+
void dump(IndentingPrintWriter writer) {
final long now = mClock.uptimeMillis();
@@ -475,6 +710,12 @@ public class WakefulnessSessionObserver {
final long prevUserActivityDurationMs = now - mPrevUserActivityTimestamp;
writer.println("previous user activity duration: " + prevUserActivityDurationMs);
writer.println("is in override timeout: " + isInOverrideTimeout());
+ writer.println("mIsInteractive: " + mIsInteractive);
+ writer.println("current screen policy: " + mCurrentScreenPolicy);
+ final long currentScreenPolicyDurationMs = now - mCurrentScreenPolicyTimestamp;
+ writer.println("current screen policy duration: " + currentScreenPolicyDurationMs);
+ writer.println("previous screen policy: " + mPrevScreenPolicy);
+ writer.println("past screen policy duration: " + mPrevScreenPolicyDurationMs);
writer.decreaseIndent();
}
}
@@ -512,6 +753,24 @@ public class WakefulnessSessionObserver {
(long) defaultTimeoutMs);
}
+ public void logDimEvent(
+ int physicalDisplayPortId,
+ @PolicyReason int policyReason,
+ @PowerManager.UserActivityEvent int userActivityEvent,
+ int lastUserActivityEventDurationMs,
+ int dimDurationMs,
+ int defaultTimeoutMs) {
+ int logUserActivityEvent = convertToLogUserActivityEvent(userActivityEvent);
+ FrameworkStatsLog.write(
+ FrameworkStatsLog.SCREEN_DIM_REPORTED,
+ physicalDisplayPortId,
+ policyReason,
+ logUserActivityEvent,
+ lastUserActivityEventDurationMs,
+ dimDurationMs,
+ defaultTimeoutMs);
+ }
+
private static final int USER_ACTIVITY_OTHER = FrameworkStatsLog
.SCREEN_INTERACTIVE_SESSION_REPORTED__LAST_USER_ACTIVITY_EVENT__OTHER;
@@ -591,5 +850,13 @@ public class WakefulnessSessionObserver {
Clock getClock() {
return SystemClock::uptimeMillis;
}
+
+ Handler getHandler() {
+ return BackgroundThread.getHandler();
+ }
+
+ DisplayManagerInternal getDisplayManagerInternal() {
+ return LocalServices.getService(DisplayManagerInternal.class);
+ }
}
}
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 7e27407fc57f..f6c3d8ef1249 100644
--- a/services/core/java/com/android/server/power/hint/HintManagerService.java
+++ b/services/core/java/com/android/server/power/hint/HintManagerService.java
@@ -76,6 +76,7 @@ import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
+import java.util.PriorityQueue;
import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.TimeUnit;
@@ -109,12 +110,31 @@ public final class HintManagerService extends SystemService {
@GuardedBy("mChannelMapLock")
private ArrayMap<Integer, TreeMap<Integer, ChannelItem>> mChannelMap;
+ /*
+ * Multi-level map storing the session statistics since last pull from StatsD.
+ * The first level is keyed by the UID of the process owning the session.
+ * The second level is keyed by the tag of the session. The point of separating different
+ * tags is that since different categories (e.g. HWUI vs APP) of the sessions may have different
+ * behaviors.
+ */
+ @GuardedBy("mSessionSnapshotMapLock")
+ private ArrayMap<Integer, ArrayMap<Integer, AppHintSessionSnapshot>> mSessionSnapshotMap;
+
/** Lock to protect mActiveSessions and the UidObserver. */
private final Object mLock = new Object();
/** Lock to protect mChannelMap. */
private final Object mChannelMapLock = new Object();
+ /*
+ * Lock to protect mSessionSnapshotMap.
+ * Nested acquisition of mSessionSnapshotMapLock and mLock should be avoided.
+ * We should grab these separately.
+ * When we need to have nested acquisitions, we should always follow the order of acquiring
+ * mSessionSnapshotMapLock first then mLock.
+ */
+ private final Object mSessionSnapshotMapLock = new Object();
+
@GuardedBy("mNonIsolatedTidsLock")
private final Map<Integer, Set<Long>> mNonIsolatedTids;
@@ -135,6 +155,8 @@ public final class HintManagerService extends SystemService {
private int mPowerHalVersion;
private final PackageManager mPackageManager;
+ private boolean mUsesFmq;
+
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";
@@ -162,6 +184,7 @@ public final class HintManagerService extends SystemService {
}
mActiveSessions = new ArrayMap<>();
mChannelMap = new ArrayMap<>();
+ mSessionSnapshotMap = new ArrayMap<>();
mNativeWrapper = injector.createNativeWrapper();
mNativeWrapper.halInit();
mHintSessionPreferredRate = mNativeWrapper.halGetHintSessionPreferredRate();
@@ -170,6 +193,7 @@ public final class HintManagerService extends SystemService {
LocalServices.getService(ActivityManagerInternal.class));
mPowerHal = injector.createIPower();
mPowerHalVersion = 0;
+ mUsesFmq = false;
if (mPowerHal != null) {
try {
mPowerHalVersion = mPowerHal.getInterfaceVersion();
@@ -197,6 +221,134 @@ public final class HintManagerService extends SystemService {
}
}
+ private class AppHintSessionSnapshot {
+ /*
+ * Per-Uid and Per-SessionTag snapshot that tracks metrics including
+ * number of created sessions, number of power efficienct sessions, and
+ * maximum number of threads in a session.
+ * Given that it's Per-SessionTag, each uid can have multiple snapshots.
+ */
+ int mCurrentSessionCount;
+ int mMaxConcurrentSession;
+ int mMaxThreadCount;
+ int mPowerEfficientSessionCount;
+
+ final int mTargetDurationNsCountPQSize = 100;
+ PriorityQueue<TargetDurationRecord> mTargetDurationNsCountPQ;
+
+ class TargetDurationRecord implements Comparable<TargetDurationRecord> {
+ long mTargetDurationNs;
+ long mTimestamp;
+ int mCount;
+ TargetDurationRecord(long targetDurationNs) {
+ mTargetDurationNs = targetDurationNs;
+ mTimestamp = System.currentTimeMillis();
+ mCount = 1;
+ }
+
+ @Override
+ public int compareTo(TargetDurationRecord t) {
+ int tCount = t.getCount();
+ int thisCount = this.getCount();
+ // Here we sort in the order of number of count in ascending order.
+ // i.e. the lowest count of target duration is at the head of the queue.
+ // Upon same count, the tiebreaker is the timestamp, the older item will be at the
+ // front of the queue.
+ if (tCount == thisCount) {
+ return (t.getTimestamp() < this.getTimestamp()) ? 1 : -1;
+ }
+ return (tCount < thisCount) ? 1 : -1;
+ }
+ long getTargetDurationNs() {
+ return mTargetDurationNs;
+ }
+
+ int getCount() {
+ return mCount;
+ }
+
+ long getTimestamp() {
+ return mTimestamp;
+ }
+
+ void setCount(int count) {
+ mCount = count;
+ }
+
+ void setTimestamp() {
+ mTimestamp = System.currentTimeMillis();
+ }
+
+ void setTargetDurationNs(long targetDurationNs) {
+ mTargetDurationNs = targetDurationNs;
+ }
+ }
+
+ AppHintSessionSnapshot() {
+ mCurrentSessionCount = 0;
+ mMaxConcurrentSession = 0;
+ mMaxThreadCount = 0;
+ mPowerEfficientSessionCount = 0;
+ mTargetDurationNsCountPQ = new PriorityQueue<>(1);
+ }
+
+ void updateUponSessionCreation(int threadCount, long targetDuration) {
+ mCurrentSessionCount += 1;
+ mMaxConcurrentSession = Math.max(mMaxConcurrentSession, mCurrentSessionCount);
+ mMaxThreadCount = Math.max(mMaxThreadCount, threadCount);
+ updateTargetDurationNs(targetDuration);
+ }
+
+ void updateUponSessionClose() {
+ mCurrentSessionCount -= 1;
+ }
+
+ void logPowerEfficientSession() {
+ mPowerEfficientSessionCount += 1;
+ }
+
+ void updateThreadCount(int threadCount) {
+ mMaxThreadCount = Math.max(mMaxThreadCount, threadCount);
+ }
+
+ void updateTargetDurationNs(long targetDurationNs) {
+ for (TargetDurationRecord t : mTargetDurationNsCountPQ) {
+ if (t.getTargetDurationNs() == targetDurationNs) {
+ t.setCount(t.getCount() + 1);
+ t.setTimestamp();
+ return;
+ }
+ }
+ if (mTargetDurationNsCountPQ.size() == mTargetDurationNsCountPQSize) {
+ mTargetDurationNsCountPQ.poll();
+ }
+ mTargetDurationNsCountPQ.add(new TargetDurationRecord(targetDurationNs));
+ }
+
+ int getMaxConcurrentSession() {
+ return mMaxConcurrentSession;
+ }
+
+ int getMaxThreadCount() {
+ return mMaxThreadCount;
+ }
+
+ int getPowerEfficientSessionCount() {
+ return mPowerEfficientSessionCount;
+ }
+
+ long[] targetDurationNsList() {
+ final int listSize = 5;
+ long[] targetDurations = new long[listSize];
+ while (mTargetDurationNsCountPQ.size() > listSize) {
+ mTargetDurationNsCountPQ.poll();
+ }
+ for (int i = 0; i < listSize && !mTargetDurationNsCountPQ.isEmpty(); ++i) {
+ targetDurations[i] = mTargetDurationNsCountPQ.poll().getTargetDurationNs();
+ }
+ return targetDurations;
+ }
+ }
private boolean isHalSupported() {
return mHintSessionPreferredRate != -1;
}
@@ -235,6 +387,11 @@ public final class HintManagerService extends SystemService {
null, // use default PullAtomMetadata values
DIRECT_EXECUTOR,
this::onPullAtom);
+ statsManager.setPullAtomCallback(
+ FrameworkStatsLog.ADPF_SESSION_SNAPSHOT,
+ null, // use default PullAtomMetadata values
+ DIRECT_EXECUTOR,
+ this::onPullAtom);
}
private int onPullAtom(int atomTag, @NonNull List<StatsEvent> data) {
@@ -247,11 +404,82 @@ public final class HintManagerService extends SystemService {
data.add(FrameworkStatsLog.buildStatsEvent(
FrameworkStatsLog.ADPF_SYSTEM_COMPONENT_INFO,
isSurfaceFlingerUsingCpuHint,
- isHwuiHintManagerEnabled));
+ isHwuiHintManagerEnabled,
+ getFmqUsage()));
+ }
+ if (atomTag == FrameworkStatsLog.ADPF_SESSION_SNAPSHOT) {
+ synchronized (mSessionSnapshotMapLock) {
+ for (int i = 0; i < mSessionSnapshotMap.size(); ++i) {
+ final int uid = mSessionSnapshotMap.keyAt(i);
+ final ArrayMap<Integer, AppHintSessionSnapshot> sessionSnapshots =
+ mSessionSnapshotMap.valueAt(i);
+ for (int j = 0; j < sessionSnapshots.size(); ++j) {
+ final int sessionTag = sessionSnapshots.keyAt(j);
+ final AppHintSessionSnapshot sessionSnapshot = sessionSnapshots.valueAt(j);
+ data.add(FrameworkStatsLog.buildStatsEvent(
+ FrameworkStatsLog.ADPF_SESSION_SNAPSHOT,
+ uid,
+ sessionTag,
+ sessionSnapshot.getMaxConcurrentSession(),
+ sessionSnapshot.getMaxThreadCount(),
+ sessionSnapshot.getPowerEfficientSessionCount(),
+ sessionSnapshot.targetDurationNsList()
+ ));
+ }
+ }
+ }
+ restoreSessionSnapshot();
}
return android.app.StatsManager.PULL_SUCCESS;
}
+ private int getFmqUsage() {
+ if (mUsesFmq) {
+ return FrameworkStatsLog.ADPFSYSTEM_COMPONENT_INFO__FMQ_SUPPORTED__SUPPORTED;
+ } else if (mPowerHalVersion < 5) {
+ return FrameworkStatsLog.ADPFSYSTEM_COMPONENT_INFO__FMQ_SUPPORTED__HAL_VERSION_NOT_MET;
+ } else {
+ return FrameworkStatsLog.ADPFSYSTEM_COMPONENT_INFO__FMQ_SUPPORTED__UNSUPPORTED;
+ }
+ }
+
+ private void restoreSessionSnapshot() {
+ // clean up snapshot map and rebuild with current active sessions
+ synchronized (mSessionSnapshotMapLock) {
+ mSessionSnapshotMap.clear();
+ synchronized (mLock) {
+ for (int i = 0; i < mActiveSessions.size(); i++) {
+ ArrayMap<IBinder, ArraySet<AppHintSession>> tokenMap =
+ mActiveSessions.valueAt(i);
+ for (int j = 0; j < tokenMap.size(); j++) {
+ ArraySet<AppHintSession> sessionSet = tokenMap.valueAt(j);
+ for (int k = 0; k < sessionSet.size(); ++k) {
+ AppHintSession appHintSession = sessionSet.valueAt(k);
+ final int tag = appHintSession.getTag();
+ final int uid = appHintSession.getUid();
+ final long targetDuationNs =
+ appHintSession.getTargetDurationNs();
+ final int threadCount = appHintSession.getThreadIds().length;
+ ArrayMap<Integer, AppHintSessionSnapshot> snapshots =
+ mSessionSnapshotMap.get(uid);
+ if (snapshots == null) {
+ snapshots = new ArrayMap<>();
+ mSessionSnapshotMap.put(uid, snapshots);
+ }
+ AppHintSessionSnapshot snapshot = snapshots.get(tag);
+ if (snapshot == null) {
+ snapshot = new AppHintSessionSnapshot();
+ snapshots.put(tag, snapshot);
+ }
+ snapshot.updateUponSessionCreation(threadCount,
+ targetDuationNs);
+ }
+ }
+ }
+ }
+ }
+ }
+
/**
* Wrapper around the static-native methods from native.
*
@@ -833,17 +1061,13 @@ public final class HintManagerService extends SystemService {
// we change the session tag to SessionTag.GAME
// as it was not previously classified
switch (getUidApplicationCategory(callingUid)) {
- case ApplicationInfo.CATEGORY_GAME:
- tag = SessionTag.GAME;
- break;
- case ApplicationInfo.CATEGORY_UNDEFINED:
+ case ApplicationInfo.CATEGORY_GAME -> tag = SessionTag.GAME;
+ case ApplicationInfo.CATEGORY_UNDEFINED ->
// We use CATEGORY_UNDEFINED to filter the case when
// PackageManager.NameNotFoundException is caught,
// which should not happen.
tag = SessionTag.APP;
- break;
- default:
- tag = SessionTag.APP;
+ default -> tag = SessionTag.APP;
}
}
@@ -889,9 +1113,15 @@ public final class HintManagerService extends SystemService {
logPerformanceHintSessionAtom(
callingUid, sessionId, durationNanos, tids, tag);
+ synchronized (mSessionSnapshotMapLock) {
+ // Update session snapshot upon session creation
+ mSessionSnapshotMap.computeIfAbsent(callingUid, k -> new ArrayMap<>())
+ .computeIfAbsent(tag, k -> new AppHintSessionSnapshot())
+ .updateUponSessionCreation(tids.length, durationNanos);
+ }
synchronized (mLock) {
- AppHintSession hs = new AppHintSession(callingUid, callingTgid, tids, token,
- halSessionPtr, durationNanos);
+ AppHintSession hs = new AppHintSession(callingUid, callingTgid, tag, tids,
+ token, halSessionPtr, durationNanos);
ArrayMap<IBinder, ArraySet<AppHintSession>> tokenMap =
mActiveSessions.get(callingUid);
if (tokenMap == null) {
@@ -904,6 +1134,8 @@ public final class HintManagerService extends SystemService {
tokenMap.put(token, sessionSet);
}
sessionSet.add(hs);
+ mUsesFmq = mUsesFmq || hasChannel(callingTgid, callingUid);
+
return hs;
}
} finally {
@@ -996,6 +1228,7 @@ public final class HintManagerService extends SystemService {
final class AppHintSession extends IHintSession.Stub implements IBinder.DeathRecipient {
protected final int mUid;
protected final int mPid;
+ protected final int mTag;
protected int[] mThreadIds;
protected final IBinder mToken;
protected long mHalSessionPtr;
@@ -1003,6 +1236,7 @@ public final class HintManagerService extends SystemService {
protected boolean mUpdateAllowedByProcState;
protected int[] mNewThreadIds;
protected boolean mPowerEfficient;
+ protected boolean mHasBeenPowerEfficient;
protected boolean mShouldForcePause;
private enum SessionModes {
@@ -1010,16 +1244,18 @@ public final class HintManagerService extends SystemService {
};
protected AppHintSession(
- int uid, int pid, int[] threadIds, IBinder token,
+ int uid, int pid, int sessionTag, int[] threadIds, IBinder token,
long halSessionPtr, long durationNanos) {
mUid = uid;
mPid = pid;
+ mTag = sessionTag;
mToken = token;
mThreadIds = threadIds;
mHalSessionPtr = halSessionPtr;
mTargetDurationNanos = durationNanos;
mUpdateAllowedByProcState = true;
mPowerEfficient = false;
+ mHasBeenPowerEfficient = false;
mShouldForcePause = false;
final boolean allowed = mUidObserver.isUidForeground(mUid);
updateHintAllowedByProcState(allowed);
@@ -1056,6 +1292,20 @@ public final class HintManagerService extends SystemService {
mNativeWrapper.halUpdateTargetWorkDuration(mHalSessionPtr, targetDurationNanos);
mTargetDurationNanos = targetDurationNanos;
}
+ synchronized (mSessionSnapshotMapLock) {
+ ArrayMap<Integer, AppHintSessionSnapshot> sessionSnapshots =
+ mSessionSnapshotMap.get(mUid);
+ if (sessionSnapshots == null) {
+ Slogf.w(TAG, "Session snapshot map is null for uid " + mUid);
+ return;
+ }
+ AppHintSessionSnapshot sessionSnapshot = sessionSnapshots.get(mTag);
+ if (sessionSnapshot == null) {
+ Slogf.w(TAG, "Session snapshot is null for uid " + mUid + " and tag " + mTag);
+ return;
+ }
+ sessionSnapshot.updateTargetDurationNs(mTargetDurationNanos);
+ }
}
@Override
@@ -1108,6 +1358,20 @@ public final class HintManagerService extends SystemService {
if (sessionSet.isEmpty()) tokenMap.remove(mToken);
if (tokenMap.isEmpty()) mActiveSessions.remove(mUid);
}
+ synchronized (mSessionSnapshotMapLock) {
+ ArrayMap<Integer, AppHintSessionSnapshot> sessionSnapshots =
+ mSessionSnapshotMap.get(mUid);
+ if (sessionSnapshots == null) {
+ Slogf.w(TAG, "Session snapshot map is null for uid " + mUid);
+ return;
+ }
+ AppHintSessionSnapshot sessionSnapshot = sessionSnapshots.get(mTag);
+ if (sessionSnapshot == null) {
+ Slogf.w(TAG, "Session snapshot is null for uid " + mUid + " and tag " + mTag);
+ return;
+ }
+ sessionSnapshot.updateUponSessionClose();
+ }
if (powerhintThreadCleanup()) {
synchronized (mNonIsolatedTidsLock) {
final int[] tids = getTidsInternal();
@@ -1191,6 +1455,21 @@ public final class HintManagerService extends SystemService {
mShouldForcePause = false;
}
}
+ synchronized (mSessionSnapshotMapLock) {
+ ArrayMap<Integer, AppHintSessionSnapshot> sessionSnapshots =
+ mSessionSnapshotMap.get(mUid);
+ if (sessionSnapshots == null) {
+ Slogf.w(TAG, "Session snapshot map is null for uid " + mUid);
+ return;
+ }
+ AppHintSessionSnapshot sessionSnapshot = sessionSnapshots.get(mTag);
+ if (sessionSnapshot == null) {
+ Slogf.w(TAG, "Session snapshot is null for uid " + mUid + " and tag "
+ + mTag);
+ return;
+ }
+ sessionSnapshot.updateThreadCount(tids.length);
+ }
}
public int[] getThreadIds() {
@@ -1231,6 +1510,26 @@ public final class HintManagerService extends SystemService {
}
mNativeWrapper.halSetMode(mHalSessionPtr, mode, enabled);
}
+ if (enabled && (mode == SessionModes.POWER_EFFICIENCY.ordinal())) {
+ if (!mHasBeenPowerEfficient) {
+ mHasBeenPowerEfficient = true;
+ synchronized (mSessionSnapshotMapLock) {
+ ArrayMap<Integer, AppHintSessionSnapshot> sessionSnapshots =
+ mSessionSnapshotMap.get(mUid);
+ if (sessionSnapshots == null) {
+ Slogf.w(TAG, "Session snapshot map is null for uid " + mUid);
+ return;
+ }
+ AppHintSessionSnapshot sessionSnapshot = sessionSnapshots.get(mTag);
+ if (sessionSnapshot == null) {
+ Slogf.w(TAG, "Session snapshot is null for uid " + mUid
+ + " and tag " + mTag);
+ return;
+ }
+ sessionSnapshot.logPowerEfficientSession();
+ }
+ }
+ }
}
@Override
@@ -1254,6 +1553,20 @@ public final class HintManagerService extends SystemService {
}
}
+ public int getUid() {
+ return mUid;
+ }
+
+ public int getTag() {
+ return mTag;
+ }
+
+ public long getTargetDurationNs() {
+ synchronized (this) {
+ return mTargetDurationNanos;
+ }
+ }
+
void validateWorkDuration(WorkDuration workDuration) {
if (DEBUG) {
Slogf.d(TAG, "WorkDuration("
diff --git a/services/core/java/com/android/server/power/stats/WifiPowerStatsCollector.java b/services/core/java/com/android/server/power/stats/WifiPowerStatsCollector.java
index 6d519ee200c2..90981ada7c31 100644
--- a/services/core/java/com/android/server/power/stats/WifiPowerStatsCollector.java
+++ b/services/core/java/com/android/server/power/stats/WifiPowerStatsCollector.java
@@ -86,8 +86,7 @@ public class WifiPowerStatsCollector extends PowerStatsCollector {
private ConsumedEnergyRetriever mConsumedEnergyRetriever;
private IntSupplier mVoltageSupplier;
private int[] mEnergyConsumerIds = new int[0];
- private WifiActivityEnergyInfo mLastWifiActivityInfo =
- new WifiActivityEnergyInfo(0, 0, 0, 0, 0, 0);
+ private WifiActivityEnergyInfo mLastWifiActivityInfo;
private NetworkStats mLastNetworkStats;
private long[] mLastConsumedEnergyUws;
private int mLastVoltageMv;
@@ -206,14 +205,21 @@ public class WifiPowerStatsCollector extends PowerStatsCollector {
return null;
}
- long rxDuration = activityInfo.getControllerRxDurationMillis()
- - mLastWifiActivityInfo.getControllerRxDurationMillis();
- long txDuration = activityInfo.getControllerTxDurationMillis()
- - mLastWifiActivityInfo.getControllerTxDurationMillis();
- long scanDuration = activityInfo.getControllerScanDurationMillis()
- - mLastWifiActivityInfo.getControllerScanDurationMillis();
- long idleDuration = activityInfo.getControllerIdleDurationMillis()
- - mLastWifiActivityInfo.getControllerIdleDurationMillis();
+ long rxDuration = 0;
+ long txDuration = 0;
+ long scanDuration = 0;
+ long idleDuration = 0;
+
+ if (mLastWifiActivityInfo != null) {
+ rxDuration = activityInfo.getControllerRxDurationMillis()
+ - mLastWifiActivityInfo.getControllerRxDurationMillis();
+ txDuration = activityInfo.getControllerTxDurationMillis()
+ - mLastWifiActivityInfo.getControllerTxDurationMillis();
+ scanDuration = activityInfo.getControllerScanDurationMillis()
+ - mLastWifiActivityInfo.getControllerScanDurationMillis();
+ idleDuration = activityInfo.getControllerIdleDurationMillis()
+ - mLastWifiActivityInfo.getControllerIdleDurationMillis();
+ }
mLayout.setDeviceRxTime(mDeviceStats, rxDuration);
mLayout.setDeviceTxTime(mDeviceStats, txDuration);
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index 0041d39f4b2b..dfccd1af3c50 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -1542,6 +1542,11 @@ public class StatsPullAtomService extends SystemService {
final long bucketDuration = Settings.Global.getLong(mContext.getContentResolver(),
NETSTATS_UID_BUCKET_DURATION, NETSTATS_UID_DEFAULT_BUCKET_DURATION_MS);
+ // Set startTime before boot so that NetworkStats includes at least one full bucket.
+ // Set endTime in the future so that NetworkStats includes everything in the active bucket.
+ final long startTime = currentTimeInMillis - elapsedMillisSinceBoot - bucketDuration;
+ final long endTime = currentTimeInMillis + bucketDuration;
+
// TODO (b/156313635): This is short-term hack to allow perfd gets updated networkStats
// history when query in every second in order to show realtime statistics. However,
// this is not a good long-term solution since NetworkStatsService will make frequent
@@ -1552,9 +1557,7 @@ public class StatsPullAtomService extends SystemService {
}
final android.app.usage.NetworkStats queryNonTaggedStats =
- getNetworkStatsManager().querySummary(
- template, currentTimeInMillis - elapsedMillisSinceBoot - bucketDuration,
- currentTimeInMillis);
+ getNetworkStatsManager().querySummary(template, startTime, endTime);
final NetworkStats nonTaggedStats =
NetworkStatsUtils.fromPublicNetworkStats(queryNonTaggedStats);
@@ -1562,9 +1565,7 @@ public class StatsPullAtomService extends SystemService {
if (!includeTags) return nonTaggedStats;
final android.app.usage.NetworkStats queryTaggedStats =
- getNetworkStatsManager().queryTaggedSummary(template,
- currentTimeInMillis - elapsedMillisSinceBoot - bucketDuration,
- currentTimeInMillis);
+ getNetworkStatsManager().queryTaggedSummary(template, startTime, endTime);
final NetworkStats taggedStats =
NetworkStatsUtils.fromPublicNetworkStats(queryTaggedStats);
queryTaggedStats.close();
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index ddbd8091b601..953aae9588dd 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -16,6 +16,7 @@
package com.android.server.trust;
+import static android.security.Flags.shouldTrustManagerListenForPrimaryAuth;
import static android.service.trust.GrantTrustResult.STATUS_UNLOCKED_BY_GRANT;
import static android.service.trust.TrustAgentService.FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE;
@@ -84,6 +85,9 @@ import com.android.internal.content.PackageMonitor;
import com.android.internal.infra.AndroidFuture;
import com.android.internal.util.DumpUtils;
import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.LockSettingsInternal;
+import com.android.internal.widget.LockSettingsStateListener;
+import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.servicewatcher.CurrentUserServiceSupplier;
import com.android.server.servicewatcher.ServiceWatcher;
@@ -159,6 +163,7 @@ public class TrustManagerService extends SystemService {
/* package */ final TrustArchive mArchive = new TrustArchive();
private final Context mContext;
+ private final LockSettingsInternal mLockSettings;
private final LockPatternUtils mLockPatternUtils;
private final KeyStoreAuthorization mKeyStoreAuthorization;
private final UserManager mUserManager;
@@ -250,6 +255,20 @@ public class TrustManagerService extends SystemService {
private final StrongAuthTracker mStrongAuthTracker;
+ // Used to subscribe to device credential auth attempts.
+ private final LockSettingsStateListener mLockSettingsStateListener =
+ new LockSettingsStateListener() {
+ @Override
+ public void onAuthenticationSucceeded(int userId) {
+ mHandler.obtainMessage(MSG_DISPATCH_UNLOCK_ATTEMPT, 1, userId).sendToTarget();
+ }
+
+ @Override
+ public void onAuthenticationFailed(int userId) {
+ mHandler.obtainMessage(MSG_DISPATCH_UNLOCK_ATTEMPT, 0, userId).sendToTarget();
+ }
+ };
+
private boolean mTrustAgentsCanRun = false;
private int mCurrentUser = UserHandle.USER_SYSTEM;
@@ -294,6 +313,7 @@ public class TrustManagerService extends SystemService {
mHandler = createHandler(injector.getLooper());
mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
+ mLockSettings = LocalServices.getService(LockSettingsInternal.class);
mLockPatternUtils = injector.getLockPatternUtils();
mKeyStoreAuthorization = injector.getKeyStoreAuthorization();
mStrongAuthTracker = new StrongAuthTracker(context, injector.getLooper());
@@ -315,6 +335,9 @@ public class TrustManagerService extends SystemService {
checkNewAgents();
mPackageMonitor.register(mContext, mHandler.getLooper(), UserHandle.ALL, true);
mReceiver.register(mContext);
+ if (shouldTrustManagerListenForPrimaryAuth()) {
+ mLockSettings.registerLockSettingsStateListener(mLockSettingsStateListener);
+ }
mLockPatternUtils.registerStrongAuthTracker(mStrongAuthTracker);
mFingerprintManager = mContext.getSystemService(FingerprintManager.class);
mFaceManager = mContext.getSystemService(FaceManager.class);
diff --git a/services/core/java/com/android/server/updates/Android.bp b/services/core/java/com/android/server/updates/Android.bp
new file mode 100644
index 000000000000..10beebb82711
--- /dev/null
+++ b/services/core/java/com/android/server/updates/Android.bp
@@ -0,0 +1,11 @@
+aconfig_declarations {
+ name: "updates_flags",
+ package: "com.android.server.updates",
+ container: "system",
+ srcs: ["*.aconfig"],
+}
+
+java_aconfig_library {
+ name: "updates_flags_lib",
+ aconfig_declarations: "updates_flags",
+}
diff --git a/services/core/java/com/android/server/updates/CertificateTransparencyLogInstallReceiver.java b/services/core/java/com/android/server/updates/CertificateTransparencyLogInstallReceiver.java
index 5565b6ffb5ac..af4025e1db7c 100644
--- a/services/core/java/com/android/server/updates/CertificateTransparencyLogInstallReceiver.java
+++ b/services/core/java/com/android/server/updates/CertificateTransparencyLogInstallReceiver.java
@@ -16,17 +16,15 @@
package com.android.server.updates;
+import android.content.Context;
+import android.content.Intent;
import android.os.FileUtils;
import android.system.ErrnoException;
import android.system.Os;
-import android.util.Base64;
import android.util.Slog;
-import com.android.internal.util.HexDump;
-
import libcore.io.Streams;
-import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
@@ -36,10 +34,7 @@ import java.io.FileFilter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
public class CertificateTransparencyLogInstallReceiver extends ConfigUpdateInstallReceiver {
@@ -52,31 +47,31 @@ public class CertificateTransparencyLogInstallReceiver extends ConfigUpdateInsta
@Override
protected void install(InputStream inputStream, int version) throws IOException {
- /* Install is complicated here because we translate the input, which is a JSON file
- * containing log information to a directory with a file per log. To support atomically
- * replacing the old configuration directory with the new there's a bunch of steps. We
- * create a new directory with the logs and then do an atomic update of the current symlink
- * to point to the new directory.
- */
+ if (!Flags.certificateTransparencyInstaller()) {
+ return;
+ }
+ // To support atomically replacing the old configuration directory with the new there's a
+ // bunch of steps. We create a new directory with the logs and then do an atomic update of
+ // the current symlink to point to the new directory.
// 1. Ensure that the update dir exists and is readable
updateDir.mkdir();
if (!updateDir.isDirectory()) {
throw new IOException("Unable to make directory " + updateDir.getCanonicalPath());
}
if (!updateDir.setReadable(true, false)) {
- throw new IOException("Unable to set permissions on " +
- updateDir.getCanonicalPath());
+ throw new IOException("Unable to set permissions on " + updateDir.getCanonicalPath());
}
File currentSymlink = new File(updateDir, "current");
File newVersion = new File(updateDir, LOGDIR_PREFIX + String.valueOf(version));
- File oldDirectory;
// 2. Handle the corner case where the new directory already exists.
if (newVersion.exists()) {
// If the symlink has already been updated then the update died between steps 7 and 8
// and so we cannot delete the directory since its in use. Instead just bump the version
// and return.
if (newVersion.getCanonicalPath().equals(currentSymlink.getCanonicalPath())) {
- writeUpdate(updateDir, updateVersion,
+ writeUpdate(
+ updateDir,
+ updateVersion,
new ByteArrayInputStream(Long.toString(version).getBytes()));
deleteOldLogDirectories();
return;
@@ -91,22 +86,12 @@ public class CertificateTransparencyLogInstallReceiver extends ConfigUpdateInsta
throw new IOException("Unable to make directory " + newVersion.getCanonicalPath());
}
if (!newVersion.setReadable(true, false)) {
- throw new IOException("Failed to set " +newVersion.getCanonicalPath() +
- " readable");
+ throw new IOException(
+ "Failed to set " + newVersion.getCanonicalPath() + " readable");
}
- // 4. For each log in the log file create the corresponding file in <new_version>/ .
- try {
- byte[] content = Streams.readFullyNoClose(inputStream);
- JSONObject json = new JSONObject(new String(content, StandardCharsets.UTF_8));
- JSONArray logs = json.getJSONArray("logs");
- for (int i = 0; i < logs.length(); i++) {
- JSONObject log = logs.getJSONObject(i);
- installLog(newVersion, log);
- }
- } catch (JSONException e) {
- throw new IOException("Failed to parse logs", e);
- }
+ // 4. Validate the log list json and move the file in <new_version>/ .
+ installLogList(newVersion, inputStream);
// 5. Create the temp symlink. We'll rename this to the target symlink to get an atomic
// update.
@@ -125,62 +110,53 @@ public class CertificateTransparencyLogInstallReceiver extends ConfigUpdateInsta
}
Slog.i(TAG, "CT log directory updated to " + newVersion.getAbsolutePath());
// 7. Update the current version information
- writeUpdate(updateDir, updateVersion,
+ writeUpdate(
+ updateDir,
+ updateVersion,
new ByteArrayInputStream(Long.toString(version).getBytes()));
// 8. Cleanup
deleteOldLogDirectories();
}
- private void installLog(File directory, JSONObject logObject) throws IOException {
+ @Override
+ protected void postInstall(Context context, Intent intent) {
+ if (!Flags.certificateTransparencyInstaller()) {
+ return;
+ }
+ }
+
+ private void installLogList(File directory, InputStream inputStream) throws IOException {
try {
- String logFilename = getLogFileName(logObject.getString("key"));
- File file = new File(directory, logFilename);
- try (OutputStreamWriter out =
- new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8)) {
- writeLogEntry(out, "key", logObject.getString("key"));
- writeLogEntry(out, "url", logObject.getString("url"));
- writeLogEntry(out, "description", logObject.getString("description"));
+ byte[] content = Streams.readFullyNoClose(inputStream);
+ if (new JSONObject(new String(content, StandardCharsets.UTF_8)).length() == 0) {
+ throw new IOException("Log list data not valid");
+ }
+
+ File file = new File(directory, "log_list.json");
+ try (FileOutputStream outputStream = new FileOutputStream(file)) {
+ outputStream.write(content);
}
if (!file.setReadable(true, false)) {
throw new IOException("Failed to set permissions on " + file.getCanonicalPath());
}
} catch (JSONException e) {
- throw new IOException("Failed to parse log", e);
- }
-
- }
-
- /**
- * Get the filename for a log based on its public key. This must be kept in sync with
- * org.conscrypt.ct.CTLogStoreImpl.
- */
- private String getLogFileName(String base64PublicKey) {
- byte[] keyBytes = Base64.decode(base64PublicKey, Base64.DEFAULT);
- try {
- byte[] id = MessageDigest.getInstance("SHA-256").digest(keyBytes);
- return HexDump.toHexString(id, false);
- } catch (NoSuchAlgorithmException e) {
- // SHA-256 is guaranteed to be available.
- throw new RuntimeException(e);
+ throw new IOException("Malformed json in log list", e);
}
}
- private void writeLogEntry(OutputStreamWriter out, String key, String value)
- throws IOException {
- out.write(key + ":" + value + "\n");
- }
-
private void deleteOldLogDirectories() throws IOException {
if (!updateDir.exists()) {
return;
}
File currentTarget = new File(updateDir, "current").getCanonicalFile();
- FileFilter filter = new FileFilter() {
- @Override
- public boolean accept(File file) {
- return !currentTarget.equals(file) && file.getName().startsWith(LOGDIR_PREFIX);
- }
- };
+ FileFilter filter =
+ new FileFilter() {
+ @Override
+ public boolean accept(File file) {
+ return !currentTarget.equals(file)
+ && file.getName().startsWith(LOGDIR_PREFIX);
+ }
+ };
for (File f : updateDir.listFiles(filter)) {
FileUtils.deleteContentsAndDir(f);
}
diff --git a/services/core/java/com/android/server/updates/flags.aconfig b/services/core/java/com/android/server/updates/flags.aconfig
new file mode 100644
index 000000000000..476cb3723c97
--- /dev/null
+++ b/services/core/java/com/android/server/updates/flags.aconfig
@@ -0,0 +1,10 @@
+package: "com.android.server.updates"
+container: "system"
+
+flag {
+ name: "certificate_transparency_installer"
+ is_exported: true
+ namespace: "network_security"
+ description: "Enable certificate transparency installer for log list data"
+ bug: "319829948"
+}
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 5be5bc5e3952..2c734127b7ea 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -47,7 +47,7 @@ import static com.android.server.accessibility.AccessibilityTraceProto.WHERE;
import static com.android.server.accessibility.AccessibilityTraceProto.WINDOW_MANAGER_SERVICE;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-import static com.android.server.wm.WindowTracing.WINSCOPE_EXT;
+import static com.android.server.wm.WindowTracingLegacy.WINSCOPE_EXT;
import android.accessibilityservice.AccessibilityTrace;
import android.animation.ObjectAnimator;
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 129cee77f971..876807485eca 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -53,7 +53,6 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.app.WindowConfiguration.activityTypeToString;
-import static android.app.WindowConfiguration.isFloating;
import static android.app.admin.DevicePolicyResources.Drawables.Source.PROFILE_SWITCH_ANIMATION;
import static android.app.admin.DevicePolicyResources.Drawables.Style.OUTLINE;
import static android.app.admin.DevicePolicyResources.Drawables.WORK_PROFILE_ICON;
@@ -65,6 +64,7 @@ import static android.content.Intent.CATEGORY_SECONDARY_HOME;
import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
import static android.content.Intent.FLAG_ACTIVITY_NO_HISTORY;
import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
+import static android.content.pm.ActivityInfo.CONFIG_RESOURCES_UNUSED;
import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT;
import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
import static android.content.pm.ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
@@ -89,12 +89,6 @@ import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER;
import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_INSETS_DECOUPLED_CONFIGURATION;
-import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_EXCLUDE_PORTRAIT_FULLSCREEN;
-import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE;
-import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM;
-import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY;
-import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_SMALL;
-import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_TO_ALIGN_WITH_SPLIT_SCREEN;
import static android.content.pm.ActivityInfo.PERSIST_ACROSS_REBOOTS;
import static android.content.pm.ActivityInfo.PERSIST_ROOT_ONLY;
import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
@@ -114,7 +108,6 @@ import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
import static android.content.res.Configuration.UI_MODE_TYPE_DESK;
import static android.content.res.Configuration.UI_MODE_TYPE_MASK;
-import static android.content.res.Configuration.UI_MODE_TYPE_VR_HEADSET;
import static android.os.Build.VERSION_CODES.HONEYCOMB;
import static android.os.Build.VERSION_CODES.O;
import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
@@ -240,11 +233,10 @@ import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_F
import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
import static com.android.server.wm.ActivityTaskManagerService.getInputDispatchingTimeoutMillisLocked;
+import static com.android.server.wm.DesktopModeLaunchParamsModifier.canEnterDesktopMode;
import static com.android.server.wm.IdentifierProto.HASH_CODE;
import static com.android.server.wm.IdentifierProto.TITLE;
import static com.android.server.wm.IdentifierProto.USER_ID;
-import static com.android.server.wm.LetterboxConfiguration.DEFAULT_LETTERBOX_ASPECT_RATIO_FOR_MULTI_WINDOW;
-import static com.android.server.wm.LetterboxConfiguration.MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO;
import static com.android.server.wm.StartingData.AFTER_TRANSACTION_COPY_TO_CLIENT;
import static com.android.server.wm.StartingData.AFTER_TRANSACTION_REMOVE_DIRECTLY;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
@@ -343,7 +335,6 @@ import android.service.contentcapture.ActivityEvent;
import android.service.dreams.DreamActivity;
import android.service.voice.IVoiceInteractionSession;
import android.util.ArraySet;
-import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.Log;
import android.util.MergedConfiguration;
@@ -485,9 +476,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// finished destroying itself.
private static final int DESTROY_TIMEOUT = 10 * 1000;
- // Rounding tolerance to be used in aspect ratio computations
- private static final float ASPECT_RATIO_ROUNDING_TOLERANCE = 0.005f;
-
final ActivityTaskManagerService mAtmService;
final ActivityCallerState mCallerState;
@NonNull
@@ -831,26 +819,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// naturally.
private boolean mInSizeCompatModeForBounds = false;
- // Whether the aspect ratio restrictions applied to the activity bounds in applyAspectRatio().
- private boolean mIsAspectRatioApplied = false;
-
- // Bounds populated in resolveFixedOrientationConfiguration when this activity is letterboxed
- // for fixed orientation. If not null, they are used as parent container in
- // resolveSizeCompatModeConfiguration and in a constructor of CompatDisplayInsets. If
- // letterboxed due to fixed orientation then aspect ratio restrictions are also respected.
- // This happens when an activity has fixed orientation which doesn't match orientation of the
- // parent because a display is ignoring orientation request or fixed to user rotation.
- // See WindowManagerService#getIgnoreOrientationRequest and
- // WindowManagerService#getFixedToUserRotation for more context.
- @Nullable
- private Rect mLetterboxBoundsForFixedOrientationAndAspectRatio;
-
- // Bounds populated in resolveAspectRatioRestriction when this activity is letterboxed for
- // aspect ratio. If not null, they are used as parent container in
- // resolveSizeCompatModeConfiguration and in a constructor of CompatDisplayInsets.
- @Nullable
- private Rect mLetterboxBoundsForAspectRatio;
-
// Whether the activity is eligible to be letterboxed for fixed orientation with respect to its
// requested orientation, even when it's letterbox for another reason (e.g., size compat mode)
// and therefore #isLetterboxedForFixedOrientationAndAspectRatio returns false.
@@ -892,8 +860,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
/** The last set {@link DropInputMode} for this activity surface. */
@DropInputMode
private int mLastDropInputMode = DropInputMode.NONE;
- /** Whether the input to this activity will be dropped during the current playing animation. */
- private boolean mIsInputDroppedForAnimation;
/**
* Whether the application has desk mode resources. Calculated and cached when
@@ -1136,11 +1102,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
pw.println(prefix + "mLastReportedConfigurations:");
mLastReportedConfiguration.dump(pw, prefix + " ");
- if (Flags.activityWindowInfoFlag()) {
- pw.print(prefix);
- pw.print("mLastReportedActivityWindowInfo=");
- pw.println(mLastReportedActivityWindowInfo);
- }
+ pw.print(prefix);
+ pw.print("mLastReportedActivityWindowInfo=");
+ pw.println(mLastReportedActivityWindowInfo);
pw.print(prefix); pw.print("CurrentConfiguration="); pw.println(getConfiguration());
if (!getRequestedOverrideConfiguration().equals(EMPTY)) {
@@ -1733,15 +1697,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
}
- /** Sets if all input will be dropped as a protection during the client-driven animation. */
- void setDropInputForAnimation(boolean isInputDroppedForAnimation) {
- if (mIsInputDroppedForAnimation == isInputDroppedForAnimation) {
- return;
- }
- mIsInputDroppedForAnimation = isInputDroppedForAnimation;
- updateUntrustedEmbeddingInputProtection();
- }
-
/**
* Sets to drop input when obscured to activity if it is embedded in untrusted mode.
*
@@ -1754,10 +1709,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
if (getSurfaceControl() == null) {
return;
}
- if (mIsInputDroppedForAnimation) {
- // Disable all input during the animation.
- setDropInputMode(DropInputMode.ALL);
- } else if (isEmbeddedInUntrustedMode()) {
+ if (isEmbeddedInUntrustedMode()) {
// Set drop input to OBSCURED when untrusted embedded.
setDropInputMode(DropInputMode.OBSCURED);
} else {
@@ -3207,7 +3159,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
@NonNull
ActivityWindowInfo getActivityWindowInfo() {
- if (!Flags.activityWindowInfoFlag() || !isAttached()) {
+ if (!isAttached()) {
return mTmpActivityWindowInfo;
}
if (isFixedRotationTransforming()) {
@@ -8330,9 +8282,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
void setLastReportedActivityWindowInfo(@NonNull ActivityWindowInfo activityWindowInfo) {
- if (Flags.activityWindowInfoFlag()) {
- mLastReportedActivityWindowInfo.set(activityWindowInfo);
- }
+ mLastReportedActivityWindowInfo.set(activityWindowInfo);
}
@Nullable
@@ -8392,7 +8342,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
* aspect ratio.
*/
boolean shouldCreateCompatDisplayInsets() {
- if (mLetterboxUiController.hasFullscreenOverride()) {
+ if (mAppCompatController.getAppCompatAspectRatioOverrides().hasFullscreenOverride()) {
// If the user has forced the applications aspect ratio to be fullscreen, don't use size
// compatibility mode in any situation. The user has been warned and therefore accepts
// the risk of the application misbehaving.
@@ -8481,10 +8431,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
fullConfig.windowConfiguration.getRotation());
}
- final Rect letterboxedContainerBounds =
- mLetterboxBoundsForFixedOrientationAndAspectRatio != null
- ? mLetterboxBoundsForFixedOrientationAndAspectRatio
- : mLetterboxBoundsForAspectRatio;
+ final Rect letterboxedContainerBounds = mAppCompatController
+ .getAppCompatAspectRatioPolicy().getLetterboxedContainerBounds();
+
// The role of CompatDisplayInsets is like the override bounds.
mCompatDisplayInsets =
new CompatDisplayInsets(
@@ -8558,10 +8507,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
newParentConfiguration = mTmpConfig;
}
- mIsAspectRatioApplied = false;
+ mAppCompatController.getAppCompatAspectRatioPolicy().reset();
mIsEligibleForFixedOrientationLetterbox = false;
- mLetterboxBoundsForFixedOrientationAndAspectRatio = null;
- mLetterboxBoundsForAspectRatio = null;
mResolveConfigHint.resolveTmpOverrides(mDisplayContent, newParentConfiguration,
isFixedRotationTransforming());
@@ -8594,8 +8541,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// If activity in fullscreen mode is letterboxed because of fixed orientation then bounds
// are already calculated in resolveFixedOrientationConfiguration.
// Don't apply aspect ratio if app is overridden to fullscreen by device user/manufacturer.
- if (Flags.immersiveAppRepositioning() && !isLetterboxedForFixedOrientationAndAspectRatio()
- && !mLetterboxUiController.hasFullscreenOverride()) {
+ if (Flags.immersiveAppRepositioning()
+ && !mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio()
+ && !mAppCompatController.getAppCompatAspectRatioOverrides()
+ .hasFullscreenOverride()) {
resolveAspectRatioRestriction(newParentConfiguration);
}
final CompatDisplayInsets compatDisplayInsets = getCompatDisplayInsets();
@@ -8615,8 +8565,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// are already calculated in resolveFixedOrientationConfiguration, or if in size compat
// mode, it should already be calculated in resolveSizeCompatModeConfiguration.
// Don't apply aspect ratio if app is overridden to fullscreen by device user/manufacturer.
- if (!Flags.immersiveAppRepositioning() && !isLetterboxedForFixedOrientationAndAspectRatio()
- && !mInSizeCompatModeForBounds && !mLetterboxUiController.hasFullscreenOverride()) {
+ if (!Flags.immersiveAppRepositioning()
+ && !mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio()
+ && !mInSizeCompatModeForBounds
+ && !mAppCompatController.getAppCompatAspectRatioOverrides()
+ .hasFullscreenOverride()) {
resolveAspectRatioRestriction(newParentConfiguration);
}
@@ -8633,14 +8587,16 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// Fixed orientation letterboxing is possible on both large screen devices
// with ignoreOrientationRequest enabled and on phones in split screen even with
// ignoreOrientationRequest disabled.
- && (mLetterboxBoundsForFixedOrientationAndAspectRatio != null
+ && (mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio()
// Limiting check for aspect ratio letterboxing to devices with enabled
// ignoreOrientationRequest. This avoids affecting phones where apps may
// not expect the change of smallestScreenWidthDp after rotation which is
// possible with this logic. Not having smallestScreenWidthDp completely
// accurate on phones shouldn't make the big difference and is expected
// to be already well-tested by apps.
- || (isIgnoreOrientationRequest && mIsAspectRatioApplied))) {
+ || (isIgnoreOrientationRequest
+ && mAppCompatController.getAppCompatAspectRatioPolicy().isAspectRatioApplied()))) {
// TODO(b/264034555): Use mDisplayContent to calculate smallestScreenWidthDp from all
// rotations and only re-calculate if parent bounds have non-orientation size change.
resolvedConfig.smallestScreenWidthDp =
@@ -8681,7 +8637,14 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
resolvedConfig.windowConfiguration.setMaxBounds(mTmpBounds);
}
- applySizeOverrideIfNeeded(newParentConfiguration, parentWindowingMode, resolvedConfig);
+ applySizeOverrideIfNeeded(
+ mDisplayContent,
+ info.applicationInfo,
+ newParentConfiguration,
+ resolvedConfig,
+ mOptOutEdgeToEdge,
+ hasFixedRotationTransform(),
+ getCompatDisplayInsets() != null);
mResolveConfigHint.resetTmpOverrides();
logAppCompatState();
@@ -8691,100 +8654,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return Rect.copyOrNull(mResolveConfigHint.mParentAppBoundsOverride);
}
- /**
- * If necessary, override configuration fields related to app bounds.
- * This will happen when the app is targeting SDK earlier than 35.
- * The insets and configuration has decoupled since SDK level 35, to make the system
- * compatible to existing apps, override the configuration with legacy metrics. In legacy
- * metrics, fields such as appBounds will exclude some of the system bar areas.
- * The override contains all potentially affected fields in Configuration, including
- * screenWidthDp, screenHeightDp, smallestScreenWidthDp, and orientation.
- * All overrides to those fields should be in this method.
- *
- * TODO: Consider integrate this with computeConfigByResolveHint()
- */
- private void applySizeOverrideIfNeeded(Configuration newParentConfiguration,
- int parentWindowingMode, Configuration inOutConfig) {
- if (mDisplayContent == null) {
- return;
- }
- final Rect parentBounds = newParentConfiguration.windowConfiguration.getBounds();
- int rotation = newParentConfiguration.windowConfiguration.getRotation();
- if (rotation == ROTATION_UNDEFINED && !isFixedRotationTransforming()) {
- rotation = mDisplayContent.getRotation();
- }
- if (!mOptOutEdgeToEdge && (!mResolveConfigHint.mUseOverrideInsetsForConfig
- || getCompatDisplayInsets() != null
- || (isFloating(parentWindowingMode)
- // Check the requested windowing mode of activity as well in case it is
- // switching between PiP and fullscreen.
- && (inOutConfig.windowConfiguration.getWindowingMode()
- == WINDOWING_MODE_UNDEFINED
- || isFloating(inOutConfig.windowConfiguration.getWindowingMode())))
- || rotation == ROTATION_UNDEFINED)) {
- // If the insets configuration decoupled logic is not enabled for the app, or the app
- // already has a compat override, or the context doesn't contain enough info to
- // calculate the override, skip the override.
- return;
- }
- // Make sure the orientation related fields will be updated by the override insets, because
- // fixed rotation has assigned the fields from display's configuration.
- if (hasFixedRotationTransform()) {
- inOutConfig.windowConfiguration.setAppBounds(null);
- inOutConfig.screenWidthDp = Configuration.SCREEN_WIDTH_DP_UNDEFINED;
- inOutConfig.screenHeightDp = Configuration.SCREEN_HEIGHT_DP_UNDEFINED;
- inOutConfig.smallestScreenWidthDp = Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED;
- inOutConfig.orientation = ORIENTATION_UNDEFINED;
- }
-
- // Override starts here.
- final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
- final int dw = rotated ? mDisplayContent.mBaseDisplayHeight
- : mDisplayContent.mBaseDisplayWidth;
- final int dh = rotated ? mDisplayContent.mBaseDisplayWidth
- : mDisplayContent.mBaseDisplayHeight;
- final Rect nonDecorInsets = mDisplayContent.getDisplayPolicy()
- .getDecorInsetsInfo(rotation, dw, dh).mOverrideNonDecorInsets;
- // This should be the only place override the configuration for ActivityRecord. Override
- // the value if not calculated yet.
- Rect outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
- if (outAppBounds == null || outAppBounds.isEmpty()) {
- inOutConfig.windowConfiguration.setAppBounds(parentBounds);
- outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
- outAppBounds.inset(nonDecorInsets);
- }
- float density = inOutConfig.densityDpi;
- if (density == Configuration.DENSITY_DPI_UNDEFINED) {
- density = newParentConfiguration.densityDpi;
- }
- density *= DisplayMetrics.DENSITY_DEFAULT_SCALE;
- if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED) {
- inOutConfig.screenWidthDp = (int) (outAppBounds.width() / density + 0.5f);
- }
- if (inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
- inOutConfig.screenHeightDp = (int) (outAppBounds.height() / density + 0.5f);
- }
- if (inOutConfig.smallestScreenWidthDp
- == Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED
- && parentWindowingMode == WINDOWING_MODE_FULLSCREEN) {
- // For the case of PIP transition and multi-window environment, the
- // smallestScreenWidthDp is handled already. Override only if the app is in
- // fullscreen.
- final DisplayInfo info = new DisplayInfo(mDisplayContent.getDisplayInfo());
- mDisplayContent.computeSizeRanges(info, rotated, dw, dh,
- mDisplayContent.getDisplayMetrics().density,
- inOutConfig, true /* overrideConfig */);
- }
-
- // It's possible that screen size will be considered in different orientation with or
- // without considering the system bar insets. Override orientation as well.
- if (inOutConfig.orientation == ORIENTATION_UNDEFINED) {
- inOutConfig.orientation =
- (inOutConfig.screenWidthDp <= inOutConfig.screenHeightDp)
- ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
- }
- }
-
private void computeConfigByResolveHint(@NonNull Configuration resolvedConfig,
@NonNull Configuration parentConfig) {
task.computeConfigResourceOverrides(resolvedConfig, parentConfig, mResolveConfigHint);
@@ -8844,11 +8713,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// letterboxed for fixed orientation. Aspect ratio restrictions are also applied if
// present. But this doesn't return true when the activity is letterboxed only because
// of aspect ratio restrictions.
- if (isLetterboxedForFixedOrientationAndAspectRatio()) {
+ if (mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio()) {
return APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_FIXED_ORIENTATION;
}
// Letterbox for limited aspect ratio.
- if (isLetterboxedForAspectRatioOnly()) {
+ if (mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForAspectRatioOnly()) {
return APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_ASPECT_RATIO;
}
@@ -8999,26 +8870,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
/**
- * Whether this activity is letterboxed for fixed orientation. If letterboxed due to fixed
- * orientation then aspect ratio restrictions are also already respected.
- *
- * <p>This happens when an activity has fixed orientation which doesn't match orientation of the
- * parent because a display setting 'ignoreOrientationRequest' is set to true. See {@link
- * WindowManagerService#getIgnoreOrientationRequest} for more context.
- */
- boolean isLetterboxedForFixedOrientationAndAspectRatio() {
- return mLetterboxBoundsForFixedOrientationAndAspectRatio != null;
- }
-
- boolean isLetterboxedForAspectRatioOnly() {
- return mLetterboxBoundsForAspectRatio != null;
- }
-
- boolean isAspectRatioApplied() {
- return mIsAspectRatioApplied;
- }
-
- /**
* Whether this activity is eligible for letterbox eduction.
*
* <p>Conditions that need to be met:
@@ -9050,7 +8901,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
* @param parentBounds are the new parent bounds passed down to the activity and should be used
* to compute the stable bounds.
* @param outStableBounds will store the stable bounds, which are the bounds with insets
- * applied, if orientation is not respected when insets are applied.
+ * applied, if orientation is not respected when insets are applied.g
* Stable bounds should be used to compute letterboxed bounds if
* orientation is not respected when insets are applied.
* @param outNonDecorBounds will store the non decor bounds, which are the bounds with non
@@ -9203,23 +9054,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
final Rect prevResolvedBounds = new Rect(resolvedBounds);
resolvedBounds.set(containingBounds);
- final float letterboxAspectRatioOverride =
- mLetterboxUiController.getFixedOrientationLetterboxAspectRatio(newParentConfig);
-
- // Aspect ratio as suggested by the system. Apps requested mix/max aspect ratio will
- // be respected in #applyAspectRatio.
- final float desiredAspectRatio;
- if (isDefaultMultiWindowLetterboxAspectRatioDesired(newParentConfig)) {
- desiredAspectRatio = DEFAULT_LETTERBOX_ASPECT_RATIO_FOR_MULTI_WINDOW;
- } else if (letterboxAspectRatioOverride > MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO) {
- desiredAspectRatio = letterboxAspectRatioOverride;
- } else {
- desiredAspectRatio = computeAspectRatio(parentBounds);
- }
-
- // Apply aspect ratio to resolved bounds
- mIsAspectRatioApplied = applyAspectRatio(resolvedBounds, containingBoundsWithInsets,
- containingBounds, desiredAspectRatio);
+ mAppCompatController.getAppCompatAspectRatioPolicy()
+ .applyDesiredAspectRatio(newParentConfig, parentBounds, resolvedBounds,
+ containingBoundsWithInsets, containingBounds);
if (compatDisplayInsets != null) {
compatDisplayInsets.getBoundsByRotation(mTmpBounds,
@@ -9247,21 +9084,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// for comparison with size compat app bounds in {@link resolveSizeCompatModeConfiguration}.
mResolveConfigHint.mTmpCompatInsets = compatDisplayInsets;
computeConfigByResolveHint(getResolvedOverrideConfiguration(), newParentConfig);
- mLetterboxBoundsForFixedOrientationAndAspectRatio = new Rect(resolvedBounds);
- }
-
- /**
- * Returns {@code true} if the default aspect ratio for a letterboxed app in multi-window mode
- * should be used.
- */
- private boolean isDefaultMultiWindowLetterboxAspectRatioDesired(
- @NonNull Configuration parentConfig) {
- if (mDisplayContent == null) {
- return false;
- }
- final int windowingMode = parentConfig.windowConfiguration.getWindowingMode();
- return WindowConfiguration.inMultiWindowMode(windowingMode)
- && !mDisplayContent.getIgnoreOrientationRequest();
+ mAppCompatController.getAppCompatAspectRatioPolicy()
+ .setLetterboxBoundsForFixedOrientationAndAspectRatio(new Rect(resolvedBounds));
}
/**
@@ -9278,7 +9102,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// Use tmp bounds to calculate aspect ratio so we can know whether the activity should use
// restricted size (resolved bounds may be the requested override bounds).
mTmpBounds.setEmpty();
- mIsAspectRatioApplied = applyAspectRatio(mTmpBounds, parentAppBounds, parentBounds);
+ mAppCompatController.getAppCompatAspectRatioPolicy()
+ .applyAspectRatioForLetterbox(mTmpBounds, parentAppBounds, parentBounds);
// If the out bounds is not empty, it means the activity cannot fill parent's app bounds,
// then they should be aligned later in #updateResolvedBoundsPosition()
if (!mTmpBounds.isEmpty()) {
@@ -9289,7 +9114,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// restrict, the bounds should be the requested override bounds.
mResolveConfigHint.mTmpOverrideDisplayInfo = getFixedRotationTransformDisplayInfo();
computeConfigByResolveHint(resolvedConfig, newParentConfiguration);
- mLetterboxBoundsForAspectRatio = new Rect(resolvedBounds);
+ mAppCompatController.getAppCompatAspectRatioPolicy()
+ .setLetterboxBoundsForAspectRatio(new Rect(resolvedBounds));
}
}
@@ -9307,7 +9133,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// activity will be displayed within them even if it is in size compat mode. They should be
// saved here before resolved bounds are overridden below.
final boolean useResolvedBounds = Flags.immersiveAppRepositioning()
- ? isAspectRatioApplied() : isLetterboxedForFixedOrientationAndAspectRatio();
+ ? mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isAspectRatioApplied()
+ : mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio();
final Rect containerBounds = useResolvedBounds
? new Rect(resolvedBounds)
: newParentConfiguration.windowConfiguration.getBounds();
@@ -9351,8 +9180,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
resolvedBounds.set(containingBounds);
// The size of floating task is fixed (only swap), so the aspect ratio is already correct.
if (!compatDisplayInsets.mIsFloating) {
- mIsAspectRatioApplied =
- applyAspectRatio(resolvedBounds, containingAppBounds, containingBounds);
+ mAppCompatController.getAppCompatAspectRatioPolicy()
+ .applyAspectRatioForLetterbox(resolvedBounds, containingAppBounds,
+ containingBounds);
}
// Use resolvedBounds to compute other override configurations such as appBounds. The bounds
@@ -9437,18 +9267,24 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
void updateSizeCompatScale(Rect resolvedAppBounds, Rect containerAppBounds) {
- // Only allow to scale down.
mSizeCompatScale = mAppCompatController.getTransparentPolicy()
.findOpaqueNotFinishingActivityBelow()
.map(activityRecord -> activityRecord.mSizeCompatScale)
- .orElseGet(() -> {
- final int contentW = resolvedAppBounds.width();
- final int contentH = resolvedAppBounds.height();
- final int viewportW = containerAppBounds.width();
- final int viewportH = containerAppBounds.height();
- return (contentW <= viewportW && contentH <= viewportH) ? 1f : Math.min(
- (float) viewportW / contentW, (float) viewportH / contentH);
- });
+ .orElseGet(() -> calculateSizeCompatScale(resolvedAppBounds, containerAppBounds));
+ }
+
+ private float calculateSizeCompatScale(Rect resolvedAppBounds, Rect containerAppBounds) {
+ final int contentW = resolvedAppBounds.width();
+ final int contentH = resolvedAppBounds.height();
+ final int viewportW = containerAppBounds.width();
+ final int viewportH = containerAppBounds.height();
+ // Allow an application to be up-scaled if its window is smaller than its
+ // original container or if it's a freeform window in desktop mode.
+ boolean shouldAllowUpscaling = !(contentW <= viewportW && contentH <= viewportH)
+ || (canEnterDesktopMode(mAtmService.mContext)
+ && getWindowingMode() == WINDOWING_MODE_FREEFORM);
+ return shouldAllowUpscaling ? Math.min(
+ (float) viewportW / contentW, (float) viewportH / contentH) : 1f;
}
private boolean isInSizeCompatModeForBounds(final Rect appBounds, final Rect containerBounds) {
@@ -9756,190 +9592,15 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return mPauseConfigurationDispatchCount > 0;
}
- private boolean applyAspectRatio(Rect outBounds, Rect containingAppBounds,
- Rect containingBounds) {
- return applyAspectRatio(outBounds, containingAppBounds, containingBounds,
- 0 /* desiredAspectRatio */);
- }
-
- /**
- * Applies aspect ratio restrictions to outBounds. If no restrictions, then no change is
- * made to outBounds.
- *
- * @return {@code true} if aspect ratio restrictions were applied.
- */
- // TODO(b/36505427): Consider moving this method and similar ones to ConfigurationContainer.
- private boolean applyAspectRatio(Rect outBounds, Rect containingAppBounds,
- Rect containingBounds, float desiredAspectRatio) {
- final float maxAspectRatio = getMaxAspectRatio();
- final Task rootTask = getRootTask();
- final float minAspectRatio = getMinAspectRatio();
- final TaskFragment organizedTf = getOrganizedTaskFragment();
- float aspectRatioToApply = desiredAspectRatio;
- if (task == null || rootTask == null
- || (maxAspectRatio < 1 && minAspectRatio < 1 && aspectRatioToApply < 1)
- // Don't set aspect ratio if we are in VR mode.
- || isInVrUiMode(getConfiguration())
- // TODO(b/232898850): Always respect aspect ratio requests.
- // Don't set aspect ratio for activity in ActivityEmbedding split.
- || (organizedTf != null && !organizedTf.fillsParent())) {
- return false;
- }
-
- final int containingAppWidth = containingAppBounds.width();
- final int containingAppHeight = containingAppBounds.height();
- final float containingRatio = computeAspectRatio(containingAppBounds);
-
- if (aspectRatioToApply < 1) {
- aspectRatioToApply = containingRatio;
- }
-
- if (maxAspectRatio >= 1 && aspectRatioToApply > maxAspectRatio) {
- aspectRatioToApply = maxAspectRatio;
- } else if (minAspectRatio >= 1 && aspectRatioToApply < minAspectRatio) {
- aspectRatioToApply = minAspectRatio;
- }
-
- int activityWidth = containingAppWidth;
- int activityHeight = containingAppHeight;
-
- if (containingRatio - aspectRatioToApply > ASPECT_RATIO_ROUNDING_TOLERANCE) {
- if (containingAppWidth < containingAppHeight) {
- // Width is the shorter side, so we use that to figure-out what the max. height
- // should be given the aspect ratio.
- activityHeight = (int) ((activityWidth * aspectRatioToApply) + 0.5f);
- } else {
- // Height is the shorter side, so we use that to figure-out what the max. width
- // should be given the aspect ratio.
- activityWidth = (int) ((activityHeight * aspectRatioToApply) + 0.5f);
- }
- } else if (aspectRatioToApply - containingRatio > ASPECT_RATIO_ROUNDING_TOLERANCE) {
- boolean adjustWidth;
- switch (getRequestedConfigurationOrientation()) {
- case ORIENTATION_LANDSCAPE:
- // Width should be the longer side for this landscape app, so we use the width
- // to figure-out what the max. height should be given the aspect ratio.
- adjustWidth = false;
- break;
- case ORIENTATION_PORTRAIT:
- // Height should be the longer side for this portrait app, so we use the height
- // to figure-out what the max. width should be given the aspect ratio.
- adjustWidth = true;
- break;
- default:
- // This app doesn't have a preferred orientation, so we keep the length of the
- // longer side, and use it to figure-out the length of the shorter side.
- if (containingAppWidth < containingAppHeight) {
- // Width is the shorter side, so we use the height to figure-out what the
- // max. width should be given the aspect ratio.
- adjustWidth = true;
- } else {
- // Height is the shorter side, so we use the width to figure-out what the
- // max. height should be given the aspect ratio.
- adjustWidth = false;
- }
- break;
- }
- if (adjustWidth) {
- activityWidth = (int) ((activityHeight / aspectRatioToApply) + 0.5f);
- } else {
- activityHeight = (int) ((activityWidth / aspectRatioToApply) + 0.5f);
- }
- }
-
- if (containingAppWidth <= activityWidth && containingAppHeight <= activityHeight) {
- // The display matches or is less than the activity aspect ratio, so nothing else to do.
- return false;
- }
-
- // Compute configuration based on max or min supported width and height.
- // Also account for the insets (e.g. display cutouts, navigation bar), which will be
- // clipped away later in {@link Task#computeConfigResourceOverrides()}, i.e., the out
- // bounds are the app bounds restricted by aspect ratio + clippable insets. Otherwise,
- // the app bounds would end up too small. To achieve this we will also add clippable insets
- // when the corresponding dimension fully fills the parent
-
- int right = activityWidth + containingAppBounds.left;
- int left = containingAppBounds.left;
- if (right >= containingAppBounds.right) {
- right = containingBounds.right;
- left = containingBounds.left;
- }
- int bottom = activityHeight + containingAppBounds.top;
- int top = containingAppBounds.top;
- if (bottom >= containingAppBounds.bottom) {
- bottom = containingBounds.bottom;
- top = containingBounds.top;
- }
- outBounds.set(left, top, right, bottom);
- return true;
- }
-
/**
* Returns the min aspect ratio of this activity.
*/
float getMinAspectRatio() {
- if (mAppCompatController.getTransparentPolicy().isRunning()) {
- return mAppCompatController.getTransparentPolicy().getInheritedMinAspectRatio();
- }
- if (info.applicationInfo == null) {
- return info.getMinAspectRatio();
- }
- if (mLetterboxUiController.shouldApplyUserMinAspectRatioOverride()) {
- return mLetterboxUiController.getUserMinAspectRatio();
- }
- if (!mLetterboxUiController.shouldOverrideMinAspectRatio()
- && !mAppCompatController.getAppCompatCameraOverrides()
- .shouldOverrideMinAspectRatioForCamera()) {
- return info.getMinAspectRatio();
- }
- if (info.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY)
- && !ActivityInfo.isFixedOrientationPortrait(
- getOverrideOrientation())) {
- return info.getMinAspectRatio();
- }
-
- if (info.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_EXCLUDE_PORTRAIT_FULLSCREEN)
- && isParentFullscreenPortrait()) {
- // We are using the parent configuration here as this is the most recent one that gets
- // passed to onConfigurationChanged when a relevant change takes place
- return info.getMinAspectRatio();
- }
-
- if (info.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_TO_ALIGN_WITH_SPLIT_SCREEN)) {
- return Math.max(mLetterboxUiController.getSplitScreenAspectRatio(),
- info.getMinAspectRatio());
- }
-
- if (info.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_LARGE)) {
- return Math.max(ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE,
- info.getMinAspectRatio());
- }
-
- if (info.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_MEDIUM)) {
- return Math.max(ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM_VALUE,
- info.getMinAspectRatio());
- }
-
- if (info.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_SMALL)) {
- return Math.max(ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_SMALL_VALUE,
- info.getMinAspectRatio());
- }
- return info.getMinAspectRatio();
- }
-
- private boolean isParentFullscreenPortrait() {
- final WindowContainer parent = getParent();
- return parent != null
- && parent.getConfiguration().orientation == ORIENTATION_PORTRAIT
- && parent.getWindowConfiguration().getWindowingMode() == WINDOWING_MODE_FULLSCREEN;
+ return mAppCompatController.getAppCompatAspectRatioPolicy().getMinAspectRatio();
}
float getMaxAspectRatio() {
- if (mAppCompatController.getTransparentPolicy().isRunning()) {
- return mAppCompatController.getTransparentPolicy().getInheritedMaxAspectRatio();
- }
- return info.getMaxAspectRatio();
+ return mAppCompatController.getAppCompatAspectRatioPolicy().getMaxAspectRatio();
}
/**
@@ -9950,18 +9611,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
/**
- * Returns the aspect ratio of the given {@code rect}.
- */
- static float computeAspectRatio(Rect rect) {
- final int width = rect.width();
- final int height = rect.height();
- if (width == 0 || height == 0) {
- return 0;
- }
- return Math.max(width, height) / (float) Math.min(width, height);
- }
-
- /**
* @return {@code true} if this activity was reparented to another display but
* {@link #ensureActivityConfiguration} is not called.
*/
@@ -10049,8 +9698,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// the combine configurations are equal, but would otherwise differ in the override config
mTmpConfig.setTo(mLastReportedConfiguration.getMergedConfiguration());
final ActivityWindowInfo newActivityWindowInfo = getActivityWindowInfo();
- final boolean isActivityWindowInfoChanged = Flags.activityWindowInfoFlag()
- && !mLastReportedActivityWindowInfo.equals(newActivityWindowInfo);
+ final boolean isActivityWindowInfoChanged =
+ !mLastReportedActivityWindowInfo.equals(newActivityWindowInfo);
if (!displayChanged && !isActivityWindowInfoChanged
&& getConfiguration().equals(mTmpConfig)) {
ProtoLog.v(WM_DEBUG_CONFIGURATION, "Configuration & display "
@@ -10187,6 +9836,15 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
*/
private boolean shouldRelaunchLocked(int changes, Configuration changesConfig) {
int configChanged = info.getRealConfigChanged();
+ if (android.content.res.Flags.handleAllConfigChanges()) {
+ if ((configChanged & CONFIG_RESOURCES_UNUSED) != 0) {
+ // Don't relaunch any activities that claim they do not use resources at all.
+ // If they still do, the onConfigurationChanged() callback will get called to
+ // let them know anyway.
+ return false;
+ }
+ }
+
boolean onlyVrUiModeChanged = onlyVrUiModeChanged(changes, changesConfig);
// Override for apps targeting pre-O sdks
@@ -10215,8 +9873,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
*/
private boolean onlyVrUiModeChanged(int changes, Configuration lastReportedConfig) {
final Configuration currentConfig = getConfiguration();
- return changes == CONFIG_UI_MODE && (isInVrUiMode(currentConfig)
- != isInVrUiMode(lastReportedConfig));
+ return changes == CONFIG_UI_MODE && (AppCompatUtils.isInVrUiMode(currentConfig)
+ != AppCompatUtils.isInVrUiMode(lastReportedConfig));
}
/**
@@ -10588,10 +10246,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return r;
}
- private static boolean isInVrUiMode(Configuration config) {
- return (config.uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_VR_HEADSET;
- }
-
private static boolean isInDeskUiMode(Configuration config) {
return (config.uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_DESK;
}
@@ -10815,16 +10469,19 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
mAppCompatController.getAppCompatCameraOverrides()
.shouldRefreshActivityViaPauseForCameraCompat());
proto.write(SHOULD_OVERRIDE_MIN_ASPECT_RATIO,
- mLetterboxUiController.shouldOverrideMinAspectRatio());
+ mAppCompatController.getAppCompatAspectRatioOverrides()
+ .shouldOverrideMinAspectRatio());
proto.write(SHOULD_IGNORE_ORIENTATION_REQUEST_LOOP,
mAppCompatController.getAppCompatOrientationOverrides()
.shouldIgnoreOrientationRequestLoop());
proto.write(SHOULD_OVERRIDE_FORCE_RESIZE_APP,
mLetterboxUiController.shouldOverrideForceResizeApp());
proto.write(SHOULD_ENABLE_USER_ASPECT_RATIO_SETTINGS,
- mLetterboxUiController.shouldEnableUserAspectRatioSettings());
+ mAppCompatController.getAppCompatAspectRatioOverrides()
+ .shouldEnableUserAspectRatioSettings());
proto.write(IS_USER_FULLSCREEN_OVERRIDE_ENABLED,
- mLetterboxUiController.isUserFullscreenOverrideEnabled());
+ mAppCompatController.getAppCompatAspectRatioOverrides()
+ .isUserFullscreenOverrideEnabled());
}
@Override
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 5b178750bf55..59b5da8eeb51 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -5183,6 +5183,10 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
String hostingType) {
if (!mStartingProcessActivities.contains(activity)) {
mStartingProcessActivities.add(activity);
+ // Let the activity with higher z-order be started first.
+ if (mStartingProcessActivities.size() > 1) {
+ mStartingProcessActivities.sort(null /* by WindowContainer#compareTo */);
+ }
} else if (mProcessNames.get(
activity.processName, activity.info.applicationInfo.uid) != null) {
// The process is already starting. Wait for it to attach.
diff --git a/services/core/java/com/android/server/wm/AppCompatAspectRatioOverrides.java b/services/core/java/com/android/server/wm/AppCompatAspectRatioOverrides.java
new file mode 100644
index 000000000000..cf008e73321e
--- /dev/null
+++ b/services/core/java/com/android/server/wm/AppCompatAspectRatioOverrides.java
@@ -0,0 +1,304 @@
+/*
+ * 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.wm;
+
+import static android.content.pm.ActivityInfo.OVERRIDE_ANY_ORIENTATION_TO_USER;
+import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO;
+import static android.content.pm.ActivityInfo.isFixedOrientationLandscape;
+import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_16_9;
+import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_3_2;
+import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_4_3;
+import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_APP_DEFAULT;
+import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_DISPLAY_SIZE;
+import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_FULLSCREEN;
+import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_SPLIT_SCREEN;
+import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_UNSET;
+import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE;
+import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE;
+import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_FULLSCREEN_OVERRIDE;
+import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_OVERRIDE;
+
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_POSITION_MULTIPLIER_CENTER;
+import static com.android.server.wm.LetterboxConfiguration.MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO;
+
+import android.annotation.NonNull;
+import android.content.pm.PackageManager;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.Rect;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.wm.utils.OptPropFactory;
+
+import java.util.function.Function;
+
+/**
+ * Encapsulates app compat configurations and overrides related to aspect ratio.
+ */
+class AppCompatAspectRatioOverrides {
+
+ private static final String TAG =
+ TAG_WITH_CLASS_NAME ? "AppCompatAspectRatioOverrides" : TAG_ATM;
+
+ @NonNull
+ private final ActivityRecord mActivityRecord;
+ @NonNull
+ private final LetterboxConfiguration mLetterboxConfiguration;
+ @NonNull
+ private final UserAspectRatioState mUserAspectRatioState;
+
+ @NonNull
+ private final OptPropFactory.OptProp mAllowMinAspectRatioOverrideOptProp;
+ @NonNull
+ private final OptPropFactory.OptProp mAllowUserAspectRatioOverrideOptProp;
+ @NonNull
+ private final OptPropFactory.OptProp mAllowUserAspectRatioFullscreenOverrideOptProp;
+ @NonNull
+ private final OptPropFactory.OptProp mAllowOrientationOverrideOptProp;
+ @NonNull
+ private final Function<Boolean, Boolean> mIsDisplayFullScreenAndInPostureProvider;
+ @NonNull
+ private final Function<Configuration, Float> mGetHorizontalPositionMultiplierProvider;
+
+ AppCompatAspectRatioOverrides(@NonNull ActivityRecord activityRecord,
+ @NonNull LetterboxConfiguration letterboxConfiguration,
+ @NonNull OptPropFactory optPropBuilder,
+ @NonNull Function<Boolean, Boolean> isDisplayFullScreenAndInPostureProvider,
+ @NonNull Function<Configuration, Float> getHorizontalPositionMultiplierProvider) {
+ mActivityRecord = activityRecord;
+ mLetterboxConfiguration = letterboxConfiguration;
+ mUserAspectRatioState = new UserAspectRatioState();
+ mIsDisplayFullScreenAndInPostureProvider = isDisplayFullScreenAndInPostureProvider;
+ mGetHorizontalPositionMultiplierProvider = getHorizontalPositionMultiplierProvider;
+ mAllowMinAspectRatioOverrideOptProp = optPropBuilder.create(
+ PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE);
+ mAllowUserAspectRatioOverrideOptProp = optPropBuilder.create(
+ PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_OVERRIDE,
+ mLetterboxConfiguration::isUserAppAspectRatioSettingsEnabled);
+ mAllowUserAspectRatioFullscreenOverrideOptProp = optPropBuilder.create(
+ PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_FULLSCREEN_OVERRIDE,
+ mLetterboxConfiguration::isUserAppAspectRatioFullscreenEnabled);
+ mAllowOrientationOverrideOptProp = optPropBuilder.create(
+ PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE);
+ }
+
+ /**
+ * Whether we should apply the min aspect ratio per-app override. When this override is applied
+ * the min aspect ratio given in the app's manifest will be overridden to the largest enabled
+ * aspect ratio treatment unless the app's manifest value is higher. The treatment will also
+ * apply if no value is provided in the manifest.
+ *
+ * <p>This method returns {@code true} when the following conditions are met:
+ * <ul>
+ * <li>Opt-out component property isn't enabled
+ * <li>Per-app override is enabled
+ * </ul>
+ */
+ boolean shouldOverrideMinAspectRatio() {
+ return mAllowMinAspectRatioOverrideOptProp.shouldEnableWithOptInOverrideAndOptOutProperty(
+ isCompatChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO));
+ }
+
+ /**
+ * Whether we should apply the user aspect ratio override to the min aspect ratio for the
+ * current app.
+ */
+ boolean shouldApplyUserMinAspectRatioOverride() {
+ if (!shouldEnableUserAspectRatioSettings()) {
+ return false;
+ }
+
+ mUserAspectRatioState.mUserAspectRatio = getUserMinAspectRatioOverrideCode();
+
+ return mUserAspectRatioState.mUserAspectRatio != USER_MIN_ASPECT_RATIO_UNSET
+ && mUserAspectRatioState.mUserAspectRatio != USER_MIN_ASPECT_RATIO_APP_DEFAULT
+ && mUserAspectRatioState.mUserAspectRatio != USER_MIN_ASPECT_RATIO_FULLSCREEN;
+ }
+
+ boolean shouldApplyUserFullscreenOverride() {
+ if (isUserFullscreenOverrideEnabled()) {
+ mUserAspectRatioState.mUserAspectRatio = getUserMinAspectRatioOverrideCode();
+
+ return mUserAspectRatioState.mUserAspectRatio == USER_MIN_ASPECT_RATIO_FULLSCREEN;
+ }
+
+ return false;
+ }
+
+ boolean isUserFullscreenOverrideEnabled() {
+ if (mAllowUserAspectRatioOverrideOptProp.isFalse()
+ || mAllowUserAspectRatioFullscreenOverrideOptProp.isFalse()
+ || !mLetterboxConfiguration.isUserAppAspectRatioFullscreenEnabled()) {
+ return false;
+ }
+ return true;
+ }
+
+ boolean isSystemOverrideToFullscreenEnabled() {
+ return isCompatChangeEnabled(OVERRIDE_ANY_ORIENTATION_TO_USER)
+ && !mAllowOrientationOverrideOptProp.isFalse()
+ && (mUserAspectRatioState.mUserAspectRatio == USER_MIN_ASPECT_RATIO_UNSET
+ || mUserAspectRatioState.mUserAspectRatio == USER_MIN_ASPECT_RATIO_FULLSCREEN);
+ }
+
+ /**
+ * Whether we should enable users to resize the current app.
+ */
+ boolean shouldEnableUserAspectRatioSettings() {
+ // We use mBooleanPropertyAllowUserAspectRatioOverride to allow apps to opt-out which has
+ // effect only if explicitly false. If mBooleanPropertyAllowUserAspectRatioOverride is null,
+ // the current app doesn't opt-out so the first part of the predicate is true.
+ return !mAllowUserAspectRatioOverrideOptProp.isFalse()
+ && mLetterboxConfiguration.isUserAppAspectRatioSettingsEnabled()
+ && mActivityRecord.mDisplayContent != null
+ && mActivityRecord.mDisplayContent.getIgnoreOrientationRequest();
+ }
+
+ boolean hasFullscreenOverride() {
+ // `mUserAspectRatio` is always initialized first in `shouldApplyUserFullscreenOverride()`.
+ return shouldApplyUserFullscreenOverride() || isSystemOverrideToFullscreenEnabled();
+ }
+
+ float getUserMinAspectRatio() {
+ switch (mUserAspectRatioState.mUserAspectRatio) {
+ case USER_MIN_ASPECT_RATIO_DISPLAY_SIZE:
+ return getDisplaySizeMinAspectRatio();
+ case USER_MIN_ASPECT_RATIO_SPLIT_SCREEN:
+ return getSplitScreenAspectRatio();
+ case USER_MIN_ASPECT_RATIO_16_9:
+ return 16 / 9f;
+ case USER_MIN_ASPECT_RATIO_4_3:
+ return 4 / 3f;
+ case USER_MIN_ASPECT_RATIO_3_2:
+ return 3 / 2f;
+ default:
+ throw new AssertionError("Unexpected user min aspect ratio override: "
+ + mUserAspectRatioState.mUserAspectRatio);
+ }
+ }
+
+ float getSplitScreenAspectRatio() {
+ // Getting the same aspect ratio that apps get in split screen.
+ final DisplayArea displayArea = mActivityRecord.getDisplayArea();
+ if (displayArea == null) {
+ return getDefaultMinAspectRatioForUnresizableApps();
+ }
+ int dividerWindowWidth =
+ getResources().getDimensionPixelSize(R.dimen.docked_stack_divider_thickness);
+ int dividerInsets =
+ getResources().getDimensionPixelSize(R.dimen.docked_stack_divider_insets);
+ int dividerSize = dividerWindowWidth - dividerInsets * 2;
+ final Rect bounds = new Rect(displayArea.getWindowConfiguration().getAppBounds());
+ if (bounds.width() >= bounds.height()) {
+ bounds.inset(/* dx */ dividerSize / 2, /* dy */ 0);
+ bounds.right = bounds.centerX();
+ } else {
+ bounds.inset(/* dx */ 0, /* dy */ dividerSize / 2);
+ bounds.bottom = bounds.centerY();
+ }
+ return AppCompatUtils.computeAspectRatio(bounds);
+ }
+
+ float getFixedOrientationLetterboxAspectRatio(@NonNull Configuration parentConfiguration) {
+ return shouldUseSplitScreenAspectRatio(parentConfiguration)
+ ? getSplitScreenAspectRatio()
+ : mActivityRecord.shouldCreateCompatDisplayInsets()
+ ? getDefaultMinAspectRatioForUnresizableApps()
+ : getDefaultMinAspectRatio();
+ }
+
+ private float getDisplaySizeMinAspectRatio() {
+ final DisplayArea displayArea = mActivityRecord.getDisplayArea();
+ if (displayArea == null) {
+ return mActivityRecord.info.getMinAspectRatio();
+ }
+ final Rect bounds = new Rect(displayArea.getWindowConfiguration().getAppBounds());
+ return AppCompatUtils.computeAspectRatio(bounds);
+ }
+
+ private boolean shouldUseSplitScreenAspectRatio(@NonNull Configuration parentConfiguration) {
+ final boolean isBookMode = mIsDisplayFullScreenAndInPostureProvider
+ .apply(/* isTabletop */false);
+ final boolean isNotCenteredHorizontally = mGetHorizontalPositionMultiplierProvider.apply(
+ parentConfiguration) != LETTERBOX_POSITION_MULTIPLIER_CENTER;
+ final boolean isTabletopMode = mIsDisplayFullScreenAndInPostureProvider
+ .apply(/* isTabletop */ true);
+ final boolean isLandscape = isFixedOrientationLandscape(
+ mActivityRecord.getOverrideOrientation());
+ final AppCompatCameraOverrides cameraOverrides =
+ mActivityRecord.mAppCompatController.getAppCompatCameraOverrides();
+ final AppCompatCameraPolicy cameraPolicy =
+ mActivityRecord.mAppCompatController.getAppCompatCameraPolicy();
+ // Don't resize to split screen size when in book mode if letterbox position is centered
+ return (isBookMode && isNotCenteredHorizontally || isTabletopMode && isLandscape)
+ || cameraOverrides.isCameraCompatSplitScreenAspectRatioAllowed()
+ && (cameraPolicy != null
+ && cameraPolicy.isTreatmentEnabledForActivity(mActivityRecord));
+ }
+
+ @VisibleForTesting
+ int getUserMinAspectRatioOverrideCode() {
+ try {
+ return mActivityRecord.mAtmService.getPackageManager()
+ .getUserMinAspectRatio(mActivityRecord.packageName, mActivityRecord.mUserId);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Exception thrown retrieving aspect ratio user override " + this, e);
+ }
+ return mUserAspectRatioState.mUserAspectRatio;
+ }
+
+ private float getDefaultMinAspectRatioForUnresizableApps() {
+ if (!mLetterboxConfiguration.getIsSplitScreenAspectRatioForUnresizableAppsEnabled()
+ || mActivityRecord.getDisplayArea() == null) {
+ return mLetterboxConfiguration.getDefaultMinAspectRatioForUnresizableApps()
+ > MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO
+ ? mLetterboxConfiguration.getDefaultMinAspectRatioForUnresizableApps()
+ : getDefaultMinAspectRatio();
+ }
+
+ return getSplitScreenAspectRatio();
+ }
+
+ private float getDefaultMinAspectRatio() {
+ if (mActivityRecord.getDisplayArea() == null
+ || !mLetterboxConfiguration
+ .getIsDisplayAspectRatioEnabledForFixedOrientationLetterbox()) {
+ return mLetterboxConfiguration.getFixedOrientationLetterboxAspectRatio();
+ }
+ return getDisplaySizeMinAspectRatio();
+ }
+
+ private static class UserAspectRatioState {
+ // TODO(b/315140179): Make mUserAspectRatio final
+ // The min aspect ratio override set by user
+ @PackageManager.UserMinAspectRatio
+ private int mUserAspectRatio = USER_MIN_ASPECT_RATIO_UNSET;
+ }
+
+ private boolean isCompatChangeEnabled(long overrideChangeId) {
+ return mActivityRecord.info.isChangeEnabled(overrideChangeId);
+ }
+
+ private Resources getResources() {
+ return mActivityRecord.mWmService.mContext.getResources();
+ }
+}
diff --git a/services/core/java/com/android/server/wm/AppCompatAspectRatioPolicy.java b/services/core/java/com/android/server/wm/AppCompatAspectRatioPolicy.java
new file mode 100644
index 000000000000..a7d2ecce4984
--- /dev/null
+++ b/services/core/java/com/android/server/wm/AppCompatAspectRatioPolicy.java
@@ -0,0 +1,379 @@
+/*
+ * 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.wm;
+
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_EXCLUDE_PORTRAIT_FULLSCREEN;
+import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE;
+import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM;
+import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY;
+import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_SMALL;
+import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_TO_ALIGN_WITH_SPLIT_SCREEN;
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+
+import static com.android.server.wm.LetterboxConfiguration.DEFAULT_LETTERBOX_ASPECT_RATIO_FOR_MULTI_WINDOW;
+import static com.android.server.wm.LetterboxConfiguration.MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.WindowConfiguration;
+import android.content.pm.ActivityInfo;
+import android.content.res.Configuration;
+import android.graphics.Rect;
+
+/**
+ * Encapsulate app compat policy logic related to aspect ratio.
+ */
+class AppCompatAspectRatioPolicy {
+
+ // Rounding tolerance to be used in aspect ratio computations
+ private static final float ASPECT_RATIO_ROUNDING_TOLERANCE = 0.005f;
+
+ @NonNull
+ private final ActivityRecord mActivityRecord;
+ @NonNull
+ private final TransparentPolicy mTransparentPolicy;
+ @NonNull
+ private final AppCompatOverrides mAppCompatOverrides;
+ @NonNull
+ private final AppCompatAspectRatioState mAppCompatAspectRatioState;
+
+ AppCompatAspectRatioPolicy(@NonNull ActivityRecord activityRecord,
+ @NonNull TransparentPolicy transparentPolicy,
+ @NonNull AppCompatOverrides appCompatOverrides) {
+ mActivityRecord = activityRecord;
+ mTransparentPolicy = transparentPolicy;
+ mAppCompatOverrides = appCompatOverrides;
+ mAppCompatAspectRatioState = new AppCompatAspectRatioState();
+ }
+
+ /**
+ * Starts the evaluation of app compat aspect ratio when a new configuration needs to be
+ * resolved.
+ */
+ void reset() {
+ mAppCompatAspectRatioState.reset();
+ }
+
+ float getDesiredAspectRatio(@NonNull Configuration newParentConfig,
+ @NonNull Rect parentBounds) {
+ final float letterboxAspectRatioOverride =
+ mAppCompatOverrides.getAppCompatAspectRatioOverrides()
+ .getFixedOrientationLetterboxAspectRatio(newParentConfig);
+ // Aspect ratio as suggested by the system. Apps requested mix/max aspect ratio will
+ // be respected in #applyAspectRatio.
+ if (isDefaultMultiWindowLetterboxAspectRatioDesired(newParentConfig)) {
+ return DEFAULT_LETTERBOX_ASPECT_RATIO_FOR_MULTI_WINDOW;
+ } else if (letterboxAspectRatioOverride > MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO) {
+ return letterboxAspectRatioOverride;
+ }
+ return AppCompatUtils.computeAspectRatio(parentBounds);
+ }
+
+ void applyDesiredAspectRatio(@NonNull Configuration newParentConfig, @NonNull Rect parentBounds,
+ @NonNull Rect resolvedBounds, @NonNull Rect containingBoundsWithInsets,
+ @NonNull Rect containingBounds) {
+ final float desiredAspectRatio = getDesiredAspectRatio(newParentConfig, parentBounds);
+ mAppCompatAspectRatioState.mIsAspectRatioApplied = applyAspectRatio(resolvedBounds,
+ containingBoundsWithInsets, containingBounds, desiredAspectRatio);
+ }
+
+ void applyAspectRatioForLetterbox(Rect outBounds, Rect containingAppBounds,
+ Rect containingBounds) {
+ mAppCompatAspectRatioState.mIsAspectRatioApplied = applyAspectRatio(outBounds,
+ containingAppBounds, containingBounds, 0 /* desiredAspectRatio */);
+ }
+
+ /**
+ * @return {@code true} when an app compat aspect ratio has been applied.
+ */
+ boolean isAspectRatioApplied() {
+ return mAppCompatAspectRatioState.mIsAspectRatioApplied;
+ }
+
+ /**
+ * Returns the min aspect ratio of this activity.
+ */
+ float getMinAspectRatio() {
+ if (mTransparentPolicy.isRunning()) {
+ return mTransparentPolicy.getInheritedMinAspectRatio();
+ }
+ final ActivityInfo info = mActivityRecord.info;
+ if (info.applicationInfo == null) {
+ return info.getMinAspectRatio();
+ }
+ final AppCompatAspectRatioOverrides aspectRatioOverrides =
+ mAppCompatOverrides.getAppCompatAspectRatioOverrides();
+ if (aspectRatioOverrides.shouldApplyUserMinAspectRatioOverride()) {
+ return aspectRatioOverrides.getUserMinAspectRatio();
+ }
+ if (!aspectRatioOverrides.shouldOverrideMinAspectRatio()
+ && !mAppCompatOverrides.getAppCompatCameraOverrides()
+ .shouldOverrideMinAspectRatioForCamera()) {
+ return info.getMinAspectRatio();
+ }
+
+ if (info.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY)
+ && !ActivityInfo.isFixedOrientationPortrait(
+ mActivityRecord.getOverrideOrientation())) {
+ return info.getMinAspectRatio();
+ }
+
+ if (info.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_EXCLUDE_PORTRAIT_FULLSCREEN)
+ && isParentFullscreenPortrait()) {
+ // We are using the parent configuration here as this is the most recent one that gets
+ // passed to onConfigurationChanged when a relevant change takes place
+ return info.getMinAspectRatio();
+ }
+
+ if (info.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_TO_ALIGN_WITH_SPLIT_SCREEN)) {
+ return Math.max(aspectRatioOverrides.getSplitScreenAspectRatio(),
+ info.getMinAspectRatio());
+ }
+
+ if (info.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_LARGE)) {
+ return Math.max(ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE,
+ info.getMinAspectRatio());
+ }
+
+ if (info.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_MEDIUM)) {
+ return Math.max(ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM_VALUE,
+ info.getMinAspectRatio());
+ }
+
+ if (info.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_SMALL)) {
+ return Math.max(ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_SMALL_VALUE,
+ info.getMinAspectRatio());
+ }
+ return info.getMinAspectRatio();
+ }
+
+ float getMaxAspectRatio() {
+ if (mTransparentPolicy.isRunning()) {
+ return mTransparentPolicy.getInheritedMaxAspectRatio();
+ }
+ return mActivityRecord.info.getMaxAspectRatio();
+ }
+
+ @Nullable
+ Rect getLetterboxedContainerBounds() {
+ return mAppCompatAspectRatioState.getLetterboxedContainerBounds();
+ }
+
+ /**
+ * Whether this activity is letterboxed for fixed orientation. If letterboxed due to fixed
+ * orientation then aspect ratio restrictions are also already respected.
+ *
+ * <p>This happens when an activity has fixed orientation which doesn't match orientation of the
+ * parent because a display setting 'ignoreOrientationRequest' is set to true. See {@link
+ * WindowManagerService#getIgnoreOrientationRequest} for more context.
+ */
+ boolean isLetterboxedForFixedOrientationAndAspectRatio() {
+ return mAppCompatAspectRatioState.isLetterboxedForFixedOrientationAndAspectRatio();
+ }
+
+ boolean isLetterboxedForAspectRatioOnly() {
+ return mAppCompatAspectRatioState.isLetterboxedForAspectRatioOnly();
+ }
+
+ void setLetterboxBoundsForFixedOrientationAndAspectRatio(@NonNull Rect bounds) {
+ mAppCompatAspectRatioState.mLetterboxBoundsForFixedOrientationAndAspectRatio = bounds;
+ }
+
+ void setLetterboxBoundsForAspectRatio(@NonNull Rect bounds) {
+ mAppCompatAspectRatioState.mLetterboxBoundsForAspectRatio = bounds;
+ }
+
+ private boolean isParentFullscreenPortrait() {
+ final WindowContainer<?> parent = mActivityRecord.getParent();
+ return parent != null
+ && parent.getConfiguration().orientation == ORIENTATION_PORTRAIT
+ && parent.getWindowConfiguration().getWindowingMode() == WINDOWING_MODE_FULLSCREEN;
+ }
+
+ /**
+ * Applies aspect ratio restrictions to outBounds. If no restrictions, then no change is
+ * made to outBounds.
+ *
+ * @return {@code true} if aspect ratio restrictions were applied.
+ */
+ private boolean applyAspectRatio(Rect outBounds, Rect containingAppBounds,
+ Rect containingBounds, float desiredAspectRatio) {
+ final float maxAspectRatio = getMaxAspectRatio();
+ final Task rootTask = mActivityRecord.getRootTask();
+ final Task task = mActivityRecord.getTask();
+ final float minAspectRatio = getMinAspectRatio();
+ final TaskFragment organizedTf = mActivityRecord.getOrganizedTaskFragment();
+ float aspectRatioToApply = desiredAspectRatio;
+ if (task == null || rootTask == null
+ || (maxAspectRatio < 1 && minAspectRatio < 1 && aspectRatioToApply < 1)
+ // Don't set aspect ratio if we are in VR mode.
+ || AppCompatUtils.isInVrUiMode(mActivityRecord.getConfiguration())
+ // TODO(b/232898850): Always respect aspect ratio requests.
+ // Don't set aspect ratio for activity in ActivityEmbedding split.
+ || (organizedTf != null && !organizedTf.fillsParent())) {
+ return false;
+ }
+
+ final int containingAppWidth = containingAppBounds.width();
+ final int containingAppHeight = containingAppBounds.height();
+ final float containingRatio = AppCompatUtils.computeAspectRatio(containingAppBounds);
+
+ if (aspectRatioToApply < 1) {
+ aspectRatioToApply = containingRatio;
+ }
+
+ if (maxAspectRatio >= 1 && aspectRatioToApply > maxAspectRatio) {
+ aspectRatioToApply = maxAspectRatio;
+ } else if (minAspectRatio >= 1 && aspectRatioToApply < minAspectRatio) {
+ aspectRatioToApply = minAspectRatio;
+ }
+
+ int activityWidth = containingAppWidth;
+ int activityHeight = containingAppHeight;
+
+ if (containingRatio - aspectRatioToApply > ASPECT_RATIO_ROUNDING_TOLERANCE) {
+ if (containingAppWidth < containingAppHeight) {
+ // Width is the shorter side, so we use that to figure-out what the max. height
+ // should be given the aspect ratio.
+ activityHeight = (int) ((activityWidth * aspectRatioToApply) + 0.5f);
+ } else {
+ // Height is the shorter side, so we use that to figure-out what the max. width
+ // should be given the aspect ratio.
+ activityWidth = (int) ((activityHeight * aspectRatioToApply) + 0.5f);
+ }
+ } else if (aspectRatioToApply - containingRatio > ASPECT_RATIO_ROUNDING_TOLERANCE) {
+ boolean adjustWidth;
+ switch (mActivityRecord.getRequestedConfigurationOrientation()) {
+ case ORIENTATION_LANDSCAPE:
+ // Width should be the longer side for this landscape app, so we use the width
+ // to figure-out what the max. height should be given the aspect ratio.
+ adjustWidth = false;
+ break;
+ case ORIENTATION_PORTRAIT:
+ // Height should be the longer side for this portrait app, so we use the height
+ // to figure-out what the max. width should be given the aspect ratio.
+ adjustWidth = true;
+ break;
+ default:
+ // This app doesn't have a preferred orientation, so we keep the length of the
+ // longer side, and use it to figure-out the length of the shorter side.
+ if (containingAppWidth < containingAppHeight) {
+ // Width is the shorter side, so we use the height to figure-out what the
+ // max. width should be given the aspect ratio.
+ adjustWidth = true;
+ } else {
+ // Height is the shorter side, so we use the width to figure-out what the
+ // max. height should be given the aspect ratio.
+ adjustWidth = false;
+ }
+ break;
+ }
+ if (adjustWidth) {
+ activityWidth = (int) ((activityHeight / aspectRatioToApply) + 0.5f);
+ } else {
+ activityHeight = (int) ((activityWidth / aspectRatioToApply) + 0.5f);
+ }
+ }
+
+ if (containingAppWidth <= activityWidth && containingAppHeight <= activityHeight) {
+ // The display matches or is less than the activity aspect ratio, so nothing else to do.
+ return false;
+ }
+
+ // Compute configuration based on max or min supported width and height.
+ // Also account for the insets (e.g. display cutouts, navigation bar), which will be
+ // clipped away later in {@link Task#computeConfigResourceOverrides()}, i.e., the out
+ // bounds are the app bounds restricted by aspect ratio + clippable insets. Otherwise,
+ // the app bounds would end up too small. To achieve this we will also add clippable insets
+ // when the corresponding dimension fully fills the parent
+
+ int right = activityWidth + containingAppBounds.left;
+ int left = containingAppBounds.left;
+ if (right >= containingAppBounds.right) {
+ right = containingBounds.right;
+ left = containingBounds.left;
+ }
+ int bottom = activityHeight + containingAppBounds.top;
+ int top = containingAppBounds.top;
+ if (bottom >= containingAppBounds.bottom) {
+ bottom = containingBounds.bottom;
+ top = containingBounds.top;
+ }
+ outBounds.set(left, top, right, bottom);
+ return true;
+ }
+
+ /**
+ * Returns {@code true} if the default aspect ratio for a letterboxed app in multi-window mode
+ * should be used.
+ */
+ private boolean isDefaultMultiWindowLetterboxAspectRatioDesired(
+ @NonNull Configuration parentConfig) {
+ final DisplayContent dc = mActivityRecord.mDisplayContent;
+ if (dc == null) {
+ return false;
+ }
+ final int windowingMode = parentConfig.windowConfiguration.getWindowingMode();
+ return WindowConfiguration.inMultiWindowMode(windowingMode)
+ && !dc.getIgnoreOrientationRequest();
+ }
+
+ private static class AppCompatAspectRatioState {
+ // Whether the aspect ratio restrictions applied to the activity bounds
+ // in applyAspectRatio().
+ private boolean mIsAspectRatioApplied = false;
+
+ // Bounds populated in resolveAspectRatioRestriction when this activity is letterboxed for
+ // aspect ratio. If not null, they are used as parent container in
+ // resolveSizeCompatModeConfiguration and in a constructor of CompatDisplayInsets.
+ @Nullable
+ private Rect mLetterboxBoundsForAspectRatio;
+ // Bounds populated in resolveFixedOrientationConfiguration when this activity is
+ // letterboxed for fixed orientation. If not null, they are used as parent container in
+ // resolveSizeCompatModeConfiguration and in a constructor of CompatDisplayInsets. If
+ // letterboxed due to fixed orientation then aspect ratio restrictions are also respected.
+ // This happens when an activity has fixed orientation which doesn't match orientation of
+ // the parent because a display is ignoring orientation request or fixed to user rotation.
+ // See WindowManagerService#getIgnoreOrientationRequest and
+ // WindowManagerService#getFixedToUserRotation for more context.
+ @Nullable
+ private Rect mLetterboxBoundsForFixedOrientationAndAspectRatio;
+
+ @Nullable
+ Rect getLetterboxedContainerBounds() {
+ return mLetterboxBoundsForFixedOrientationAndAspectRatio != null
+ ? mLetterboxBoundsForFixedOrientationAndAspectRatio
+ : mLetterboxBoundsForAspectRatio;
+ }
+
+ void reset() {
+ mIsAspectRatioApplied = false;
+ mLetterboxBoundsForFixedOrientationAndAspectRatio = null;
+ mLetterboxBoundsForAspectRatio = null;
+ }
+
+ boolean isLetterboxedForFixedOrientationAndAspectRatio() {
+ return mLetterboxBoundsForFixedOrientationAndAspectRatio != null;
+ }
+
+ boolean isLetterboxedForAspectRatioOnly() {
+ return mLetterboxBoundsForAspectRatio != null;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/wm/AppCompatController.java b/services/core/java/com/android/server/wm/AppCompatController.java
index 16d3787b5e74..3eed96dd90c2 100644
--- a/services/core/java/com/android/server/wm/AppCompatController.java
+++ b/services/core/java/com/android/server/wm/AppCompatController.java
@@ -33,6 +33,8 @@ class AppCompatController {
@NonNull
private final AppCompatOrientationPolicy mOrientationPolicy;
@NonNull
+ private final AppCompatAspectRatioPolicy mAppCompatAspectRatioPolicy;
+ @NonNull
private final AppCompatOverrides mAppCompatOverrides;
AppCompatController(@NonNull WindowManagerService wmService,
@@ -45,12 +47,9 @@ class AppCompatController {
wmService.mLetterboxConfiguration);
mAppCompatOverrides = new AppCompatOverrides(activityRecord,
wmService.mLetterboxConfiguration, optPropBuilder);
- // TODO(b/341903757) Remove BooleanSuppliers after fixing dependency with aspectRatio.
- final LetterboxUiController tmpController = activityRecord.mLetterboxUiController;
- mOrientationPolicy = new AppCompatOrientationPolicy(activityRecord,
- mAppCompatOverrides, tmpController::shouldApplyUserFullscreenOverride,
- tmpController::shouldApplyUserMinAspectRatioOverride,
- tmpController::isSystemOverrideToFullscreenEnabled);
+ mOrientationPolicy = new AppCompatOrientationPolicy(activityRecord, mAppCompatOverrides);
+ mAppCompatAspectRatioPolicy = new AppCompatAspectRatioPolicy(activityRecord,
+ mTransparentPolicy, mAppCompatOverrides);
}
@NonNull
@@ -64,6 +63,11 @@ class AppCompatController {
}
@NonNull
+ AppCompatAspectRatioPolicy getAppCompatAspectRatioPolicy() {
+ return mAppCompatAspectRatioPolicy;
+ }
+
+ @NonNull
AppCompatOverrides getAppCompatOverrides() {
return mAppCompatOverrides;
}
@@ -78,6 +82,11 @@ class AppCompatController {
return mAppCompatOverrides.getAppCompatCameraOverrides();
}
+ @NonNull
+ AppCompatAspectRatioOverrides getAppCompatAspectRatioOverrides() {
+ return mAppCompatOverrides.getAppCompatAspectRatioOverrides();
+ }
+
@Nullable
AppCompatCameraPolicy getAppCompatCameraPolicy() {
if (mActivityRecord.mDisplayContent != null) {
diff --git a/services/core/java/com/android/server/wm/AppCompatOrientationOverrides.java b/services/core/java/com/android/server/wm/AppCompatOrientationOverrides.java
index 155e246db7de..9bf80119e431 100644
--- a/services/core/java/com/android/server/wm/AppCompatOrientationOverrides.java
+++ b/services/core/java/com/android/server/wm/AppCompatOrientationOverrides.java
@@ -50,7 +50,6 @@ class AppCompatOrientationOverrides {
private final ActivityRecord mActivityRecord;
@NonNull
private final AppCompatCameraOverrides mAppCompatCameraOverrides;
-
@NonNull
private final OptPropFactory.OptProp mIgnoreRequestedOrientationOptProp;
@NonNull
@@ -109,7 +108,8 @@ class AppCompatOrientationOverrides {
mOrientationOverridesState.updateOrientationRequestLoopState();
return mOrientationOverridesState.shouldIgnoreRequestInLoop()
- && !mActivityRecord.isLetterboxedForFixedOrientationAndAspectRatio();
+ && !mActivityRecord.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio();
}
/**
diff --git a/services/core/java/com/android/server/wm/AppCompatOrientationPolicy.java b/services/core/java/com/android/server/wm/AppCompatOrientationPolicy.java
index 69ba59b9ff49..17f0d970d043 100644
--- a/services/core/java/com/android/server/wm/AppCompatOrientationPolicy.java
+++ b/services/core/java/com/android/server/wm/AppCompatOrientationPolicy.java
@@ -32,8 +32,6 @@ import android.annotation.NonNull;
import android.content.pm.ActivityInfo;
import android.util.Slog;
-import java.util.function.BooleanSupplier;
-
/**
* Contains all the logic related to orientation in the context of app compatibility
*/
@@ -46,24 +44,11 @@ class AppCompatOrientationPolicy {
@NonNull
private final AppCompatOverrides mAppCompatOverrides;
- @NonNull
- private final BooleanSupplier mShouldApplyUserFullscreenOverride;
- @NonNull
- private final BooleanSupplier mShouldApplyUserMinAspectRatioOverride;
- @NonNull
- private final BooleanSupplier mIsSystemOverrideToFullscreenEnabled;
- // TODO(b/341903757) Remove BooleanSuppliers after fixing dependency with spectRatio component
AppCompatOrientationPolicy(@NonNull ActivityRecord activityRecord,
- @NonNull AppCompatOverrides appCompatOverrides,
- @NonNull BooleanSupplier shouldApplyUserFullscreenOverride,
- @NonNull BooleanSupplier shouldApplyUserMinAspectRatioOverride,
- @NonNull BooleanSupplier isSystemOverrideToFullscreenEnabled) {
+ @NonNull AppCompatOverrides appCompatOverrides) {
mActivityRecord = activityRecord;
mAppCompatOverrides = appCompatOverrides;
- mShouldApplyUserFullscreenOverride = shouldApplyUserFullscreenOverride;
- mShouldApplyUserMinAspectRatioOverride = shouldApplyUserMinAspectRatioOverride;
- mIsSystemOverrideToFullscreenEnabled = isSystemOverrideToFullscreenEnabled;
}
@ActivityInfo.ScreenOrientation
@@ -71,7 +56,9 @@ class AppCompatOrientationPolicy {
final DisplayContent displayContent = mActivityRecord.mDisplayContent;
final boolean isIgnoreOrientationRequestEnabled = displayContent != null
&& displayContent.getIgnoreOrientationRequest();
- if (mShouldApplyUserFullscreenOverride.getAsBoolean() && isIgnoreOrientationRequestEnabled
+ final boolean shouldApplyUserFullscreenOverride = mAppCompatOverrides
+ .getAppCompatAspectRatioOverrides().shouldApplyUserFullscreenOverride();
+ if (shouldApplyUserFullscreenOverride && isIgnoreOrientationRequestEnabled
// Do not override orientation to fullscreen for camera activities.
// Fixed-orientation activities are rarely tested in other orientations, and it
// often results in sideways or stretched previews. As the camera compat treatment
@@ -88,8 +75,9 @@ class AppCompatOrientationPolicy {
// In some cases (e.g. Kids app) we need to map the candidate orientation to some other
// orientation.
candidate = mActivityRecord.mWmService.mapOrientationRequest(candidate);
-
- if (mShouldApplyUserMinAspectRatioOverride.getAsBoolean() && (!isFixedOrientation(candidate)
+ final boolean shouldApplyUserMinAspectRatioOverride = mAppCompatOverrides
+ .getAppCompatAspectRatioOverrides().shouldApplyUserMinAspectRatioOverride();
+ if (shouldApplyUserMinAspectRatioOverride && (!isFixedOrientation(candidate)
|| candidate == SCREEN_ORIENTATION_LOCKED)) {
Slog.v(TAG, "Requested orientation " + screenOrientationToString(candidate)
+ " for " + mActivityRecord + " is overridden to "
@@ -113,7 +101,9 @@ class AppCompatOrientationPolicy {
// mUserAspectRatio is always initialized first in shouldApplyUserFullscreenOverride(),
// which will always come first before this check as user override > device
// manufacturer override.
- if (mIsSystemOverrideToFullscreenEnabled.getAsBoolean() && isIgnoreOrientationRequestEnabled
+ final boolean isSystemOverrideToFullscreenEnabled = mAppCompatOverrides
+ .getAppCompatAspectRatioOverrides().isSystemOverrideToFullscreenEnabled();
+ if (isSystemOverrideToFullscreenEnabled && isIgnoreOrientationRequestEnabled
// Do not override orientation to fullscreen for camera activities.
// Fixed-orientation activities are rarely tested in other orientations, and it
// often results in sideways or stretched previews. As the camera compat treatment
diff --git a/services/core/java/com/android/server/wm/AppCompatOverrides.java b/services/core/java/com/android/server/wm/AppCompatOverrides.java
index 94c6ba90866c..f6f93f9eda7c 100644
--- a/services/core/java/com/android/server/wm/AppCompatOverrides.java
+++ b/services/core/java/com/android/server/wm/AppCompatOverrides.java
@@ -18,20 +18,13 @@ package com.android.server.wm;
import static android.content.pm.ActivityInfo.FORCE_NON_RESIZE_APP;
import static android.content.pm.ActivityInfo.FORCE_RESIZE_APP;
-import static android.content.pm.ActivityInfo.OVERRIDE_ANY_ORIENTATION_TO_USER;
import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS;
-import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO;
import static android.content.pm.ActivityInfo.OVERRIDE_RESPECT_REQUESTED_ORIENTATION;
import static android.content.pm.ActivityInfo.OVERRIDE_USE_DISPLAY_LANDSCAPE_NATURAL_ORIENTATION;
-import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_FULLSCREEN;
-import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_UNSET;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_DISPLAY_ORIENTATION_OVERRIDE;
-import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE;
import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE;
import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES;
-import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_FULLSCREEN_OVERRIDE;
-import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_OVERRIDE;
import static android.view.WindowManager.PROPERTY_COMPAT_ENABLE_FAKE_FOCUS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
@@ -61,17 +54,13 @@ public class AppCompatOverrides {
@NonNull
private final OptPropFactory.OptProp mAllowDisplayOrientationOverrideOptProp;
@NonNull
- private final OptPropFactory.OptProp mAllowMinAspectRatioOverrideOptProp;
- @NonNull
private final OptPropFactory.OptProp mAllowForceResizeOverrideOptProp;
@NonNull
- private final OptPropFactory.OptProp mAllowUserAspectRatioOverrideOptProp;
- @NonNull
- private final OptPropFactory.OptProp mAllowUserAspectRatioFullscreenOverrideOptProp;
- @NonNull
private final AppCompatOrientationOverrides mAppCompatOrientationOverrides;
@NonNull
private final AppCompatCameraOverrides mAppCompatCameraOverrides;
+ @NonNull
+ private final AppCompatAspectRatioOverrides mAppCompatAspectRatioOverrides;
AppCompatOverrides(@NonNull ActivityRecord activityRecord,
@NonNull LetterboxConfiguration letterboxConfiguration,
@@ -83,6 +72,11 @@ public class AppCompatOverrides {
mLetterboxConfiguration, optPropBuilder);
mAppCompatOrientationOverrides = new AppCompatOrientationOverrides(mActivityRecord,
mLetterboxConfiguration, optPropBuilder, mAppCompatCameraOverrides);
+ // TODO(b/341903757) Remove BooleanSuppliers after fixing dependency with reachability.
+ mAppCompatAspectRatioOverrides = new AppCompatAspectRatioOverrides(activityRecord,
+ mLetterboxConfiguration, optPropBuilder,
+ activityRecord.mLetterboxUiController::isDisplayFullScreenAndInPosture,
+ activityRecord.mLetterboxUiController::getHorizontalPositionMultiplier);
mFakeFocusOptProp = optPropBuilder.create(PROPERTY_COMPAT_ENABLE_FAKE_FOCUS,
mLetterboxConfiguration::isCompatFakeFocusEnabled);
@@ -101,16 +95,8 @@ public class AppCompatOverrides {
== ORIENTATION_LANDSCAPE
);
- mAllowMinAspectRatioOverrideOptProp = optPropBuilder.create(
- PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE);
mAllowForceResizeOverrideOptProp = optPropBuilder.create(
PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES);
- mAllowUserAspectRatioOverrideOptProp = optPropBuilder.create(
- PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_OVERRIDE,
- mLetterboxConfiguration::isUserAppAspectRatioSettingsEnabled);
- mAllowUserAspectRatioFullscreenOverrideOptProp = optPropBuilder.create(
- PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_FULLSCREEN_OVERRIDE,
- mLetterboxConfiguration::isUserAppAspectRatioFullscreenEnabled);
}
@NonNull
@@ -123,6 +109,11 @@ public class AppCompatOverrides {
return mAppCompatCameraOverrides;
}
+ @NonNull
+ AppCompatAspectRatioOverrides getAppCompatAspectRatioOverrides() {
+ return mAppCompatAspectRatioOverrides;
+ }
+
/**
* Whether sending compat fake focus for split screen resumed activities is enabled. Needed
* because some game engines wait to get focus before drawing the content of the app which isn't
@@ -140,34 +131,10 @@ public class AppCompatOverrides {
isCompatChangeEnabled(OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS));
}
- boolean isSystemOverrideToFullscreenEnabled(int userAspectRatio) {
- return isCompatChangeEnabled(OVERRIDE_ANY_ORIENTATION_TO_USER)
- && !mAllowOrientationOverrideOptProp.isFalse()
- && (userAspectRatio == USER_MIN_ASPECT_RATIO_UNSET
- || userAspectRatio == USER_MIN_ASPECT_RATIO_FULLSCREEN);
- }
-
boolean isAllowOrientationOverrideOptOut() {
return mAllowOrientationOverrideOptProp.isFalse();
}
- /**
- * Whether we should apply the min aspect ratio per-app override. When this override is applied
- * the min aspect ratio given in the app's manifest will be overridden to the largest enabled
- * aspect ratio treatment unless the app's manifest value is higher. The treatment will also
- * apply if no value is provided in the manifest.
- *
- * <p>This method returns {@code true} when the following conditions are met:
- * <ul>
- * <li>Opt-out component property isn't enabled
- * <li>Per-app override is enabled
- * </ul>
- */
- boolean shouldOverrideMinAspectRatio() {
- return mAllowMinAspectRatioOverrideOptProp.shouldEnableWithOptInOverrideAndOptOutProperty(
- isCompatChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO));
- }
-
boolean isOverrideRespectRequestedOrientationEnabled() {
return isCompatChangeEnabled(OVERRIDE_RESPECT_REQUESTED_ORIENTATION);
}
@@ -209,28 +176,6 @@ public class AppCompatOverrides {
}
/**
- * Whether we should enable users to resize the current app.
- */
- boolean shouldEnableUserAspectRatioSettings() {
- // We use mBooleanPropertyAllowUserAspectRatioOverride to allow apps to opt-out which has
- // effect only if explicitly false. If mBooleanPropertyAllowUserAspectRatioOverride is null,
- // the current app doesn't opt-out so the first part of the predicate is true.
- return !mAllowUserAspectRatioOverrideOptProp.isFalse()
- && mLetterboxConfiguration.isUserAppAspectRatioSettingsEnabled()
- && mActivityRecord.mDisplayContent != null
- && mActivityRecord.mDisplayContent.getIgnoreOrientationRequest();
- }
-
- boolean isUserFullscreenOverrideEnabled() {
- if (mAllowUserAspectRatioOverrideOptProp.isFalse()
- || mAllowUserAspectRatioFullscreenOverrideOptProp.isFalse()
- || !mLetterboxConfiguration.isUserAppAspectRatioFullscreenEnabled()) {
- return false;
- }
- return true;
- }
-
- /**
* Whether we should apply the force non resize per-app override. When this override is applied
* it forces the packages it is applied to to be non-resizable.
*
diff --git a/services/core/java/com/android/server/wm/AppCompatUtils.java b/services/core/java/com/android/server/wm/AppCompatUtils.java
index be51dd3bcf1c..1b30a20d3e9a 100644
--- a/services/core/java/com/android/server/wm/AppCompatUtils.java
+++ b/services/core/java/com/android/server/wm/AppCompatUtils.java
@@ -16,7 +16,12 @@
package com.android.server.wm;
+import static android.content.res.Configuration.UI_MODE_TYPE_MASK;
+import static android.content.res.Configuration.UI_MODE_TYPE_VR_HEADSET;
+
import android.annotation.NonNull;
+import android.content.res.Configuration;
+import android.graphics.Rect;
import java.util.function.BooleanSupplier;
@@ -48,4 +53,24 @@ class AppCompatUtils {
}
};
}
+
+ /**
+ * Returns the aspect ratio of the given {@code rect}.
+ */
+ static float computeAspectRatio(Rect rect) {
+ final int width = rect.width();
+ final int height = rect.height();
+ if (width == 0 || height == 0) {
+ return 0;
+ }
+ return Math.max(width, height) / (float) Math.min(width, height);
+ }
+
+ /**
+ * @param config The current {@link Configuration}
+ * @return {@code true} if using a VR headset.
+ */
+ static boolean isInVrUiMode(Configuration config) {
+ return (config.uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_VR_HEADSET;
+ }
}
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index 44b414f1ea7e..78636a7870cf 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -98,7 +98,6 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayDeque;
import java.util.ArrayList;
-import java.util.function.Consumer;
import java.util.function.Predicate;
/**
@@ -290,12 +289,10 @@ public class AppTransitionController {
getTopApp(mDisplayContent.mChangingContainers, false /* ignoreHidden */);
final WindowManager.LayoutParams animLp = getAnimLp(animLpActivity);
- // Check if there is any override
- if (!overrideWithTaskFragmentRemoteAnimation(transit, activityTypes)) {
- // Unfreeze the windows that were previously frozen for TaskFragment animation.
- unfreezeEmbeddedChangingWindows();
- overrideWithRemoteAnimationIfSet(animLpActivity, transit, activityTypes);
- }
+ // No AE remote animation with Shell transition.
+ // Unfreeze the windows that were previously frozen for TaskFragment animation.
+ unfreezeEmbeddedChangingWindows();
+ overrideWithRemoteAnimationIfSet(animLpActivity, transit, activityTypes);
final boolean voiceInteraction = containsVoiceInteraction(mDisplayContent.mClosingApps)
|| containsVoiceInteraction(mDisplayContent.mOpeningApps);
@@ -726,64 +723,6 @@ public class AppTransitionController {
}
/**
- * Overrides the pending transition with the remote animation defined by the
- * {@link ITaskFragmentOrganizer} if all windows in the transition are children of
- * {@link TaskFragment} that are organized by the same organizer.
- *
- * @return {@code true} if the transition is overridden.
- */
- private boolean overrideWithTaskFragmentRemoteAnimation(@TransitionOldType int transit,
- ArraySet<Integer> activityTypes) {
- if (transitionMayContainNonAppWindows(transit)) {
- return false;
- }
- if (!transitionContainsTaskFragmentWithBoundsOverride()) {
- // No need to play TaskFragment remote animation if all embedded TaskFragment in the
- // transition fill the Task.
- return false;
- }
-
- final Task task = findParentTaskForAllEmbeddedWindows();
- final ITaskFragmentOrganizer organizer = findTaskFragmentOrganizer(task);
- final RemoteAnimationDefinition definition = organizer != null
- ? mDisplayContent.mAtmService.mTaskFragmentOrganizerController
- .getRemoteAnimationDefinition(organizer)
- : null;
- final RemoteAnimationAdapter adapter = definition != null
- ? definition.getAdapter(transit, activityTypes)
- : null;
- if (adapter == null) {
- return false;
- }
- mDisplayContent.mAppTransition.overridePendingAppTransitionRemote(
- adapter, false /* sync */, true /*isActivityEmbedding*/);
- ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
- "Override with TaskFragment remote animation for transit=%s",
- AppTransition.appTransitionOldToString(transit));
-
- final int organizerUid = mDisplayContent.mAtmService.mTaskFragmentOrganizerController
- .getTaskFragmentOrganizerUid(organizer);
- final boolean shouldDisableInputForRemoteAnimation = !task.isFullyTrustedEmbedding(
- organizerUid);
- final RemoteAnimationController remoteAnimationController =
- mDisplayContent.mAppTransition.getRemoteAnimationController();
- if (shouldDisableInputForRemoteAnimation && remoteAnimationController != null) {
- // We are going to use client-driven animation, Disable all input on activity windows
- // during the animation (unless it is fully trusted) to ensure it is safe to allow
- // client to animate the surfaces.
- // This is needed for all activity windows in the animation Task.
- remoteAnimationController.setOnRemoteAnimationReady(() -> {
- final Consumer<ActivityRecord> updateActivities =
- activity -> activity.setDropInputForAnimation(true);
- task.forAllActivities(updateActivities);
- });
- ProtoLog.d(WM_DEBUG_APP_TRANSITIONS, "Task=%d contains embedded TaskFragment."
- + " Disabled all input during TaskFragment remote animation.", task.mTaskId);
- }
- return true;
- }
-
- /**
* Overrides the pending transition with the remote animation defined for the transition in the
* set of defined remote animations in the app window token.
*/
diff --git a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
index a4fb95964a5c..54024e92f95f 100644
--- a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
+++ b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
@@ -128,21 +128,24 @@ public class BackgroundActivityStartController {
// TODO(b/263368846) Rename when ASM logic is moved in
@Retention(SOURCE)
- @IntDef({BAL_BLOCK,
- BAL_ALLOW_DEFAULT,
- BAL_ALLOW_ALLOWLISTED_UID,
+ @IntDef({
BAL_ALLOW_ALLOWLISTED_COMPONENT,
- BAL_ALLOW_VISIBLE_WINDOW,
+ BAL_ALLOW_ALLOWLISTED_UID,
+ BAL_ALLOW_BOUND_BY_FOREGROUND,
+ BAL_ALLOW_DEFAULT,
+ BAL_ALLOW_FOREGROUND,
+ BAL_ALLOW_GRACE_PERIOD,
BAL_ALLOW_PENDING_INTENT,
BAL_ALLOW_PERMISSION,
BAL_ALLOW_SAW_PERMISSION,
- BAL_ALLOW_GRACE_PERIOD,
- BAL_ALLOW_FOREGROUND,
- BAL_ALLOW_SDK_SANDBOX
+ BAL_ALLOW_SDK_SANDBOX,
+ BAL_ALLOW_TOKEN,
+ BAL_ALLOW_VISIBLE_WINDOW,
+ BAL_BLOCK
})
public @interface BalCode {}
- static final int BAL_BLOCK = 0;
+ static final int BAL_BLOCK = FrameworkStatsLog.BAL_ALLOWED__ALLOWED_REASON__BAL_BLOCKED;
static final int BAL_ALLOW_DEFAULT =
FrameworkStatsLog.BAL_ALLOWED__ALLOWED_REASON__BAL_ALLOW_DEFAULT;
@@ -195,10 +198,19 @@ public class BackgroundActivityStartController {
static final int BAL_ALLOW_NON_APP_VISIBLE_WINDOW =
FrameworkStatsLog.BAL_ALLOWED__ALLOWED_REASON__BAL_ALLOW_NON_APP_VISIBLE_WINDOW;
+ /** Process belongs to a SDK sandbox */
+ static final int BAL_ALLOW_TOKEN =
+ FrameworkStatsLog.BAL_ALLOWED__ALLOWED_REASON__BAL_ALLOW_TOKEN;
+
+ /** Process belongs to a SDK sandbox */
+ static final int BAL_ALLOW_BOUND_BY_FOREGROUND =
+ FrameworkStatsLog.BAL_ALLOWED__ALLOWED_REASON__BAL_ALLOW_BOUND_BY_FOREGROUND;
+
static String balCodeToString(@BalCode int balCode) {
return switch (balCode) {
case BAL_ALLOW_ALLOWLISTED_COMPONENT -> "BAL_ALLOW_ALLOWLISTED_COMPONENT";
case BAL_ALLOW_ALLOWLISTED_UID -> "BAL_ALLOW_ALLOWLISTED_UID";
+ case BAL_ALLOW_BOUND_BY_FOREGROUND -> "BAL_ALLOW_BOUND_BY_FOREGROUND";
case BAL_ALLOW_DEFAULT -> "BAL_ALLOW_DEFAULT";
case BAL_ALLOW_FOREGROUND -> "BAL_ALLOW_FOREGROUND";
case BAL_ALLOW_GRACE_PERIOD -> "BAL_ALLOW_GRACE_PERIOD";
@@ -207,6 +219,7 @@ public class BackgroundActivityStartController {
case BAL_ALLOW_PERMISSION -> "BAL_ALLOW_PERMISSION";
case BAL_ALLOW_SAW_PERMISSION -> "BAL_ALLOW_SAW_PERMISSION";
case BAL_ALLOW_SDK_SANDBOX -> "BAL_ALLOW_SDK_SANDBOX";
+ case BAL_ALLOW_TOKEN -> "BAL_ALLOW_TOKEN";
case BAL_ALLOW_VISIBLE_WINDOW -> "BAL_ALLOW_VISIBLE_WINDOW";
case BAL_BLOCK -> "BAL_BLOCK";
default -> throw new IllegalArgumentException("Unexpected value: " + balCode);
@@ -1042,7 +1055,9 @@ public class BackgroundActivityStartController {
|| balCode == BAL_ALLOW_PENDING_INTENT
|| balCode == BAL_ALLOW_SAW_PERMISSION
|| balCode == BAL_ALLOW_VISIBLE_WINDOW
- || balCode == BAL_ALLOW_NON_APP_VISIBLE_WINDOW) {
+ || balCode == BAL_ALLOW_NON_APP_VISIBLE_WINDOW
+ || balCode == BAL_ALLOW_TOKEN
+ || balCode == BAL_ALLOW_BOUND_BY_FOREGROUND) {
return true;
}
}
@@ -1266,7 +1281,8 @@ public class BackgroundActivityStartController {
|| balCode == BAL_ALLOW_PERMISSION
|| balCode == BAL_ALLOW_SAW_PERMISSION
|| balCode == BAL_ALLOW_VISIBLE_WINDOW
- || balCode == BAL_ALLOW_NON_APP_VISIBLE_WINDOW) {
+ || balCode == BAL_ALLOW_NON_APP_VISIBLE_WINDOW
+ || balCode == BAL_ALLOW_BOUND_BY_FOREGROUND) {
return;
}
@@ -1572,7 +1588,7 @@ public class BackgroundActivityStartController {
}
if (balCode == BAL_ALLOW_VISIBLE_WINDOW || balCode == BAL_ALLOW_NON_APP_VISIBLE_WINDOW
- || balCode == BAL_ALLOW_FOREGROUND) {
+ || balCode == BAL_ALLOW_FOREGROUND || balCode == BAL_ALLOW_BOUND_BY_FOREGROUND) {
Task task = sourceRecord != null ? sourceRecord.getTask() : targetTask;
if (task != null && task.getDisplayArea() != null) {
joiner.add(prefix + "Tasks: ");
@@ -1659,6 +1675,8 @@ public class BackgroundActivityStartController {
activityName = "";
}
writeBalAllowedLog(activityName, finalVerdict.getCode(), state);
+ } else {
+ writeBalAllowedLogMinimal(state);
}
} else {
@BalCode int code = finalVerdict.getCode();
@@ -1723,6 +1741,24 @@ public class BackgroundActivityStartController {
);
}
+ @VisibleForTesting void writeBalAllowedLogMinimal(BalState state) {
+ FrameworkStatsLog.write(FrameworkStatsLog.BAL_ALLOWED,
+ "",
+ BAL_ALLOW_DEFAULT,
+ NO_PROCESS_UID,
+ NO_PROCESS_UID,
+ state.mResultForCaller == null ? BAL_BLOCK : state.mResultForCaller.getRawCode(),
+ state.mBalAllowedByPiCreator.allowsBackgroundActivityStarts(),
+ state.callerExplicitOptInOrOut(),
+ state.mResultForRealCaller == null ? BAL_BLOCK
+ : state.mResultForRealCaller.getRawCode(),
+ state.mBalAllowedByPiSender.allowsBackgroundActivityStarts(),
+ state.realCallerExplicitOptInOrOut(),
+ getTargetSdk(state.mCallingPackage),
+ getTargetSdk(state.mRealCallingPackage)
+ );
+ }
+
/**
* Called whenever an activity finishes. Stores the record, so it can be used by ASM grace
* period checks.
diff --git a/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java b/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java
index 478524b7bd1c..4a870a3a5b6e 100644
--- a/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java
+++ b/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java
@@ -23,10 +23,13 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLAS
import static com.android.server.wm.ActivityTaskManagerService.ACTIVITY_BG_START_GRACE_PERIOD_MS;
import static com.android.server.wm.ActivityTaskManagerService.APP_SWITCH_ALLOW;
import static com.android.server.wm.ActivityTaskManagerService.APP_SWITCH_DISALLOW;
+import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_BOUND_BY_FOREGROUND;
import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_FOREGROUND;
import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_GRACE_PERIOD;
import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_PERMISSION;
+import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_TOKEN;
import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_VISIBLE_WINDOW;
+import static com.android.window.flags.Flags.balImprovedMetrics;
import static java.util.Objects.requireNonNull;
@@ -110,8 +113,8 @@ class BackgroundLaunchProcessController {
}
// Allow if the flag was explicitly set.
if (isBackgroundStartAllowedByToken(uid, packageName, isCheckingForFgsStart)) {
- return new BalVerdict(BAL_ALLOW_PERMISSION, /*background*/ true,
- "process allowed by token");
+ return new BalVerdict(balImprovedMetrics() ? BAL_ALLOW_TOKEN : BAL_ALLOW_PERMISSION,
+ /*background*/ true, "process allowed by token");
}
// Allow if the caller is bound by a UID that's currently foreground.
// But still respect the appSwitchState.
@@ -120,7 +123,8 @@ class BackgroundLaunchProcessController {
? appSwitchState != APP_SWITCH_DISALLOW && isBoundByForegroundUid()
: isBoundByForegroundUid();
if (allowBoundByForegroundUid) {
- return new BalVerdict(BAL_ALLOW_VISIBLE_WINDOW, /*background*/ false,
+ return new BalVerdict(balImprovedMetrics() ? BAL_ALLOW_BOUND_BY_FOREGROUND
+ : BAL_ALLOW_VISIBLE_WINDOW, /*background*/ false,
"process bound by foreground uid");
}
// Allow if the caller has an activity in any foreground task.
diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java
index efd52026cfec..a38ac9ba4b75 100644
--- a/services/core/java/com/android/server/wm/ConfigurationContainer.java
+++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java
@@ -22,14 +22,23 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.app.WindowConfiguration.activityTypeToString;
+import static android.app.WindowConfiguration.isFloating;
import static android.app.WindowConfiguration.windowingModeToString;
import static android.app.WindowConfigurationProto.WINDOWING_MODE;
import static android.content.ConfigurationProto.WINDOW_CONFIGURATION;
+import static android.content.pm.ActivityInfo.INSETS_DECOUPLED_CONFIGURATION_ENFORCED;
+import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_INSETS_DECOUPLED_CONFIGURATION;
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
+import static android.view.Surface.ROTATION_270;
+import static android.view.Surface.ROTATION_90;
import static com.android.server.wm.ConfigurationContainerProto.FULL_CONFIGURATION;
import static com.android.server.wm.ConfigurationContainerProto.MERGED_OVERRIDE_CONFIGURATION;
@@ -38,11 +47,14 @@ import static com.android.server.wm.ConfigurationContainerProto.OVERRIDE_CONFIGU
import android.annotation.CallSuper;
import android.annotation.NonNull;
import android.app.WindowConfiguration;
+import android.content.pm.ApplicationInfo;
import android.content.res.Configuration;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.LocaleList;
+import android.util.DisplayMetrics;
import android.util.proto.ProtoOutputStream;
+import android.view.DisplayInfo;
import com.android.internal.annotations.VisibleForTesting;
@@ -173,6 +185,111 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> {
mResolvedOverrideConfiguration.setTo(mRequestedOverrideConfiguration);
}
+ /**
+ * If necessary, override configuration fields related to app bounds.
+ * This will happen when the app is targeting SDK earlier than 35.
+ * The insets and configuration has decoupled since SDK level 35, to make the system
+ * compatible to existing apps, override the configuration with legacy metrics. In legacy
+ * metrics, fields such as appBounds will exclude some of the system bar areas.
+ * The override contains all potentially affected fields in Configuration, including
+ * screenWidthDp, screenHeightDp, smallestScreenWidthDp, and orientation.
+ * All overrides to those fields should be in this method.
+ *
+ * TODO: Consider integrate this with computeConfigByResolveHint()
+ */
+ static void applySizeOverrideIfNeeded(DisplayContent displayContent, ApplicationInfo appInfo,
+ Configuration newParentConfiguration, Configuration inOutConfig,
+ boolean optOutEdgeToEdge, boolean hasFixedRotationTransform,
+ boolean hasCompatDisplayInsets) {
+ if (displayContent == null) {
+ return;
+ }
+ final boolean useOverrideInsetsForConfig =
+ displayContent.mWmService.mFlags.mInsetsDecoupledConfiguration
+ ? !appInfo.isChangeEnabled(INSETS_DECOUPLED_CONFIGURATION_ENFORCED)
+ && !appInfo.isChangeEnabled(
+ OVERRIDE_ENABLE_INSETS_DECOUPLED_CONFIGURATION)
+ : appInfo.isChangeEnabled(OVERRIDE_ENABLE_INSETS_DECOUPLED_CONFIGURATION);
+ final int parentWindowingMode =
+ newParentConfiguration.windowConfiguration.getWindowingMode();
+ final boolean isFloating = isFloating(parentWindowingMode)
+ // Check the requested windowing mode of activity as well in case it is
+ // switching between PiP and fullscreen.
+ && (inOutConfig.windowConfiguration.getWindowingMode() == WINDOWING_MODE_UNDEFINED
+ || isFloating(inOutConfig.windowConfiguration.getWindowingMode()));
+ final Rect parentBounds = newParentConfiguration.windowConfiguration.getBounds();
+ int rotation = newParentConfiguration.windowConfiguration.getRotation();
+ if (rotation == ROTATION_UNDEFINED && !hasFixedRotationTransform) {
+ rotation = displayContent.getRotation();
+ }
+ if (!optOutEdgeToEdge && (!useOverrideInsetsForConfig
+ || hasCompatDisplayInsets
+ || isFloating
+ || rotation == ROTATION_UNDEFINED)) {
+ // If the insets configuration decoupled logic is not enabled for the app, or the app
+ // already has a compat override, or the context doesn't contain enough info to
+ // calculate the override, skip the override.
+ return;
+ }
+ // Make sure the orientation related fields will be updated by the override insets, because
+ // fixed rotation has assigned the fields from display's configuration.
+ if (hasFixedRotationTransform) {
+ inOutConfig.windowConfiguration.setAppBounds(null);
+ inOutConfig.screenWidthDp = Configuration.SCREEN_WIDTH_DP_UNDEFINED;
+ inOutConfig.screenHeightDp = Configuration.SCREEN_HEIGHT_DP_UNDEFINED;
+ inOutConfig.smallestScreenWidthDp = Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED;
+ inOutConfig.orientation = ORIENTATION_UNDEFINED;
+ }
+
+ // Override starts here.
+ final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
+ final int dw = rotated
+ ? displayContent.mBaseDisplayHeight
+ : displayContent.mBaseDisplayWidth;
+ final int dh = rotated
+ ? displayContent.mBaseDisplayWidth
+ : displayContent.mBaseDisplayHeight;
+ final Rect nonDecorFrame = displayContent.getDisplayPolicy()
+ .getDecorInsetsInfo(rotation, dw, dh).mOverrideNonDecorFrame;
+ // This should be the only place override the configuration for ActivityRecord. Override
+ // the value if not calculated yet.
+ Rect outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
+ if (outAppBounds == null || outAppBounds.isEmpty()) {
+ inOutConfig.windowConfiguration.setAppBounds(parentBounds);
+ outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
+ outAppBounds.intersect(nonDecorFrame);
+ }
+ float density = inOutConfig.densityDpi;
+ if (density == Configuration.DENSITY_DPI_UNDEFINED) {
+ density = newParentConfiguration.densityDpi;
+ }
+ density *= DisplayMetrics.DENSITY_DEFAULT_SCALE;
+ if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED) {
+ inOutConfig.screenWidthDp = (int) (outAppBounds.width() / density + 0.5f);
+ }
+ if (inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
+ inOutConfig.screenHeightDp = (int) (outAppBounds.height() / density + 0.5f);
+ }
+ if (inOutConfig.smallestScreenWidthDp == Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED
+ && parentWindowingMode == WINDOWING_MODE_FULLSCREEN) {
+ // For the case of PIP transition and multi-window environment, the
+ // smallestScreenWidthDp is handled already. Override only if the app is in
+ // fullscreen.
+ final DisplayInfo info = new DisplayInfo(displayContent.getDisplayInfo());
+ displayContent.computeSizeRanges(info, rotated, dw, dh,
+ displayContent.getDisplayMetrics().density,
+ inOutConfig, true /* overrideConfig */);
+ }
+
+ // It's possible that screen size will be considered in different orientation with or
+ // without considering the system bar insets. Override orientation as well.
+ if (inOutConfig.orientation == ORIENTATION_UNDEFINED) {
+ inOutConfig.orientation = (inOutConfig.screenWidthDp <= inOutConfig.screenHeightDp)
+ ? ORIENTATION_PORTRAIT
+ : ORIENTATION_LANDSCAPE;
+ }
+ }
+
/** Returns {@code true} if requested override override configuration is not empty. */
boolean hasRequestedOverrideConfiguration() {
return mHasOverrideConfiguration;
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index a8aa0ba1f5e7..3652c4d11cb3 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1754,6 +1754,82 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
return mDisplayRotation.updateOrientation(orientation, forceUpdate);
}
+ @Nullable
+ private ActivityRecord getLastOrientationSourceApp() {
+ final WindowContainer<?> orientationSrc = getLastOrientationSource();
+ return orientationSrc != null ? orientationSrc.asActivityRecord() : null;
+ }
+
+ /**
+ * This is called when the display rotation is changed. If the current top activity which
+ * decides the display orientation is not opaque, all non-top visible activities with
+ * different fixed orientations will still keep their original appearances.
+ */
+ void applyFixedRotationForNonTopVisibleActivityIfNeeded() {
+ if (!mWmService.mFlags.mRespectNonTopVisibleFixedOrientation) {
+ return;
+ }
+ final ActivityRecord orientationSrcApp = getLastOrientationSourceApp();
+ if (orientationSrcApp == null || orientationSrcApp.fillsParent()) {
+ return;
+ }
+ final int topOrientation = orientationSrcApp.getRequestedOrientation();
+ if (topOrientation == SCREEN_ORIENTATION_UNSPECIFIED) {
+ return;
+ }
+ forAllActivities(ar -> {
+ if (!ar.isVisibleRequested()) {
+ return true;
+ }
+ applyFixedRotationForNonTopVisibleActivityIfNeeded(ar, topOrientation);
+ return false;
+ }, true /* traverseTopToBottom */);
+ }
+
+ /**
+ * This is called when a non-top activity becomes visible. Such when moving a task which
+ * contains 2 activities with different fixed orientations, and if the top one is translucent,
+ * then the bottom one will apply the fixed rotation transform for its orientation.
+ */
+ void applyFixedRotationForNonTopVisibleActivityIfNeeded(@NonNull ActivityRecord ar) {
+ if (!mWmService.mFlags.mRespectNonTopVisibleFixedOrientation) {
+ return;
+ }
+ final ActivityRecord orientationSrcApp = getLastOrientationSourceApp();
+ if (orientationSrcApp != null) {
+ applyFixedRotationForNonTopVisibleActivityIfNeeded(ar,
+ orientationSrcApp.getRequestedOrientation());
+ }
+ }
+
+ /**
+ * If the given visible activity uses a different fixed orientation than the current top, the
+ * fixed rotation transform will be applied to respect its requested appearance.
+ */
+ private void applyFixedRotationForNonTopVisibleActivityIfNeeded(@NonNull ActivityRecord ar,
+ @ActivityInfo.ScreenOrientation int topOrientation) {
+ final int orientation = ar.getRequestedOrientation();
+ if (orientation == topOrientation || ar.inMultiWindowMode()
+ || ar.getRequestedConfigurationOrientation() == ORIENTATION_UNDEFINED) {
+ return;
+ }
+ final int displayRotation = getRotation();
+ final int rotation = ar.isVisible()
+ ? ar.getWindowConfiguration().getDisplayRotation()
+ : mDisplayRotation.rotationForOrientation(orientation, displayRotation);
+ if (rotation == displayRotation) {
+ return;
+ }
+ startFixedRotationTransform(ar, rotation);
+ final WindowState wallpaperTarget = mWallpaperController.getWallpaperTarget();
+ if (wallpaperTarget != null && wallpaperTarget.mActivityRecord == ar) {
+ final WindowState wp = mWallpaperController.getTopVisibleWallpaper();
+ if (wp != null) {
+ wp.mToken.linkFixedRotationTransform(ar);
+ }
+ }
+ }
+
@Override
boolean isSyncFinished(BLASTSyncEngine.SyncGroup group) {
// Do not consider children because if they are requested to be synced, they should be
@@ -1822,10 +1898,23 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
return false;
}
if (r.hasFixedRotationTransform()) {
+ if (mWmService.mFlags.mRespectNonTopVisibleFixedOrientation
+ && mFixedRotationLaunchingApp == null) {
+ // It could be finishing the previous top translucent activity, and the next fixed
+ // orientation activity becomes the current top.
+ setFixedRotationLaunchingAppUnchecked(r,
+ r.getWindowConfiguration().getDisplayRotation());
+ }
// It has been set and not yet finished.
return true;
}
- if (!r.occludesParent() || r.isReportedDrawn()) {
+ if (mWmService.mFlags.mRespectNonTopVisibleFixedOrientation) {
+ if (r.isReportedDrawn()) {
+ // It is late for a drawn app. Either this is already a stable state or it needs
+ // a rotation animation to handle the change.
+ return false;
+ }
+ } else if (!r.occludesParent() || r.isReportedDrawn()) {
// While entering or leaving a translucent or floating activity (e.g. dialog style),
// there is a visible activity in the background. Then it still needs rotation animation
// to cover the activity configuration change.
@@ -6923,7 +7012,11 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
// In most cases this is a no-op if the activity doesn't have fixed rotation.
// Otherwise it could be from finishing recents animation while the display has
// different orientation.
- r.finishFixedRotationTransform();
+ if (!mWmService.mFlags.mRespectNonTopVisibleFixedOrientation) {
+ r.finishFixedRotationTransform();
+ } else if (!r.isVisible()) {
+ r.finishFixedRotationTransform();
+ }
return;
}
if (mFixedRotationLaunchingApp.hasFixedRotationTransform(r)) {
@@ -6938,7 +7031,12 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
// E.g. activity A transferred starting window to B, only A will receive transition
// finished event. A doesn't have fixed rotation but B is the rotated launching app.
final Task task = r.getTask();
- if (task == null || task != mFixedRotationLaunchingApp.getTask()) {
+ if (task != mFixedRotationLaunchingApp.getTask()
+ // When closing a translucent task A (r.fillsParent() is false) to a
+ // visible task B, because only A has visibility change, there is only A's
+ // transition callback. Then it still needs to update orientation for B.
+ && (!mWmService.mFlags.mRespectNonTopVisibleFixedOrientation
+ || r.fillsParent())) {
// Different tasks won't be in one activity transition animation.
return;
}
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index c67928aeeb5d..d2976b01acbb 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -627,6 +627,7 @@ public class DisplayRotation {
mRotation = rotation;
+ mDisplayContent.applyFixedRotationForNonTopVisibleActivityIfNeeded();
mDisplayContent.setLayoutNeeded();
mDisplayContent.mWaitingForConfig = true;
diff --git a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
index f40eb24fd5eb..3123018e9e88 100644
--- a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
+++ b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
@@ -174,6 +174,9 @@ class EnsureActivitiesVisibleHelper {
// First: if this is not the current activity being started, make
// sure it matches the current configuration.
if (r != mStarting && mNotifyClients) {
+ if (!isTop) {
+ r.mDisplayContent.applyFixedRotationForNonTopVisibleActivityIfNeeded(r);
+ }
r.ensureActivityConfiguration(true /* ignoreVisibility */);
}
diff --git a/services/core/java/com/android/server/wm/LetterboxConfiguration.java b/services/core/java/com/android/server/wm/LetterboxConfiguration.java
index b5af8065726d..0161ae5b5473 100644
--- a/services/core/java/com/android/server/wm/LetterboxConfiguration.java
+++ b/services/core/java/com/android/server/wm/LetterboxConfiguration.java
@@ -19,7 +19,6 @@ package com.android.server.wm;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import android.annotation.DimenRes;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -29,11 +28,11 @@ import android.provider.DeviceConfig;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.wm.utils.DimenPxIntSupplier;
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 {
@@ -308,34 +307,6 @@ final class LetterboxConfiguration {
// Flags dynamically updated with {@link android.provider.DeviceConfig}.
@NonNull private final SynchedDeviceConfig mDeviceConfig;
- // Cached version of IntSupplier customised to evaluate new dimen in pixels
- // when density changes
- private static class DimenPxIntSupplier implements IntSupplier {
-
- @NonNull
- private final Context mContext;
-
- private final int mResourceId;
-
- private float mLastDensity = Float.MIN_VALUE;
- private int mValue = 0;
-
- private DimenPxIntSupplier(@NonNull Context context, @DimenRes int resourceId) {
- mContext = context;
- mResourceId = resourceId;
- }
-
- @Override
- public int getAsInt() {
- final float newDensity = mContext.getResources().getDisplayMetrics().density;
- if (newDensity != mLastDensity) {
- mLastDensity = newDensity;
- mValue = mContext.getResources().getDimensionPixelSize(mResourceId);
- }
- return mValue;
- }
- }
-
LetterboxConfiguration(@NonNull final Context systemUiContext) {
this(systemUiContext, new LetterboxConfigurationPersister(
() -> readLetterboxHorizontalReachabilityPositionFromConfig(
diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java
index a3550bcb8cf5..235d6cd09d35 100644
--- a/services/core/java/com/android/server/wm/LetterboxUiController.java
+++ b/services/core/java/com/android/server/wm/LetterboxUiController.java
@@ -17,15 +17,6 @@
package com.android.server.wm;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static android.content.pm.ActivityInfo.isFixedOrientationLandscape;
-import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_16_9;
-import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_3_2;
-import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_4_3;
-import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_APP_DEFAULT;
-import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_DISPLAY_SIZE;
-import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_FULLSCREEN;
-import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_SPLIT_SCREEN;
-import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_UNSET;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
@@ -44,7 +35,6 @@ import static com.android.internal.util.FrameworkStatsLog.LETTERBOX_POSITION_CHA
import static com.android.internal.util.FrameworkStatsLog.LETTERBOX_POSITION_CHANGED__POSITION_CHANGE__LEFT_TO_CENTER;
import static com.android.internal.util.FrameworkStatsLog.LETTERBOX_POSITION_CHANGED__POSITION_CHANGE__RIGHT_TO_CENTER;
import static com.android.internal.util.FrameworkStatsLog.LETTERBOX_POSITION_CHANGED__POSITION_CHANGE__TOP_TO_CENTER;
-import static com.android.server.wm.ActivityRecord.computeAspectRatio;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND;
@@ -54,23 +44,18 @@ import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_BACKGROUND_
import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER;
import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT;
import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT;
-import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_POSITION_MULTIPLIER_CENTER;
import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM;
import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER;
import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP;
-import static com.android.server.wm.LetterboxConfiguration.MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO;
import static com.android.server.wm.LetterboxConfiguration.letterboxBackgroundTypeToString;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager.TaskDescription;
-import android.content.pm.PackageManager;
import android.content.res.Configuration;
-import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.Point;
import android.graphics.Rect;
-import android.os.RemoteException;
import android.util.Slog;
import android.view.InsetsSource;
import android.view.InsetsState;
@@ -80,7 +65,6 @@ import android.view.SurfaceControl.Transaction;
import android.view.WindowInsets;
import android.view.WindowManager;
-import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.statusbar.LetterboxDetails;
import com.android.server.wm.LetterboxConfiguration.LetterboxBackgroundType;
@@ -103,11 +87,6 @@ final class LetterboxUiController {
private boolean mShowWallpaperForLetterboxBackground;
- // TODO(b/315140179): Make mUserAspectRatio final
- // The min aspect ratio override set by user
- @PackageManager.UserMinAspectRatio
- private int mUserAspectRatio = USER_MIN_ASPECT_RATIO_UNSET;
-
@Nullable
private Letterbox mLetterbox;
@@ -154,22 +133,6 @@ final class LetterboxUiController {
}
/**
- * Whether we should apply the min aspect ratio per-app override. When this override is applied
- * the min aspect ratio given in the app's manifest will be overridden to the largest enabled
- * aspect ratio treatment unless the app's manifest value is higher. The treatment will also
- * apply if no value is provided in the manifest.
- *
- * <p>This method returns {@code true} when the following conditions are met:
- * <ul>
- * <li>Opt-out component property isn't enabled
- * <li>Per-app override is enabled
- * </ul>
- */
- boolean shouldOverrideMinAspectRatio() {
- return getAppCompatOverrides().shouldOverrideMinAspectRatio();
- }
-
- /**
* Whether we should apply the force resize per-app override. When this override is applied it
* forces the packages it is applied to to be resizable. It won't change whether the app can be
* put into multi-windowing mode, but allow the app to resize without going into size-compat
@@ -230,10 +193,6 @@ final class LetterboxUiController {
return getAppCompatOverrides().shouldUseDisplayLandscapeNaturalOrientation();
}
- private boolean isCompatChangeEnabled(long overrideChangeId) {
- return mActivityRecord.info.isChangeEnabled(overrideChangeId);
- }
-
boolean hasWallpaperBackgroundForLetterbox() {
return mShowWallpaperForLetterboxBackground;
}
@@ -395,7 +354,7 @@ final class LetterboxUiController {
// be a TaskFragment, and its windowing mode is always MULTI_WINDOW, even if the task is
// actually fullscreen. If display is still in transition e.g. unfolding, don't return true
// for HALF_FOLDED state or app will flicker.
- private boolean isDisplayFullScreenAndInPosture(boolean isTabletop) {
+ boolean isDisplayFullScreenAndInPosture(boolean isTabletop) {
Task task = mActivityRecord.getTask();
return mActivityRecord.mDisplayContent != null && task != null
&& mActivityRecord.mDisplayContent.getDisplayRotation().isDeviceInPosture(
@@ -444,48 +403,14 @@ final class LetterboxUiController {
}
float getFixedOrientationLetterboxAspectRatio(@NonNull Configuration parentConfiguration) {
- return shouldUseSplitScreenAspectRatio(parentConfiguration)
- ? getSplitScreenAspectRatio()
- : mActivityRecord.shouldCreateCompatDisplayInsets()
- ? getDefaultMinAspectRatioForUnresizableApps()
- : getDefaultMinAspectRatio();
+ return mActivityRecord.mAppCompatController.getAppCompatAspectRatioOverrides()
+ .getFixedOrientationLetterboxAspectRatio(parentConfiguration);
}
boolean isLetterboxEducationEnabled() {
return mLetterboxConfiguration.getIsEducationEnabled();
}
- private boolean shouldUseSplitScreenAspectRatio(@NonNull Configuration parentConfiguration) {
- final boolean isBookMode = isDisplayFullScreenAndInPosture(/* isTabletop */ false);
- final boolean isNotCenteredHorizontally = getHorizontalPositionMultiplier(
- parentConfiguration) != LETTERBOX_POSITION_MULTIPLIER_CENTER;
- final boolean isTabletopMode = isDisplayFullScreenAndInPosture(/* isTabletop */ true);
- final boolean isLandscape = isFixedOrientationLandscape(
- mActivityRecord.getOverrideOrientation());
- final AppCompatCameraOverrides appCompatCameraOverrides =
- mActivityRecord.mAppCompatController.getAppCompatCameraOverrides();
- final AppCompatCameraPolicy cameraPolicy =
- mActivityRecord.mAppCompatController.getAppCompatCameraPolicy();
- final boolean isCameraCompatTreatmentActive = cameraPolicy != null
- && cameraPolicy.isTreatmentEnabledForActivity(mActivityRecord);
- // Don't resize to split screen size when in book mode if letterbox position is centered
- return (isBookMode && isNotCenteredHorizontally || isTabletopMode && isLandscape)
- || (appCompatCameraOverrides.isCameraCompatSplitScreenAspectRatioAllowed()
- && isCameraCompatTreatmentActive);
- }
-
- private float getDefaultMinAspectRatioForUnresizableApps() {
- if (!mLetterboxConfiguration.getIsSplitScreenAspectRatioForUnresizableAppsEnabled()
- || mActivityRecord.getDisplayArea() == null) {
- return mLetterboxConfiguration.getDefaultMinAspectRatioForUnresizableApps()
- > MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO
- ? mLetterboxConfiguration.getDefaultMinAspectRatioForUnresizableApps()
- : getDefaultMinAspectRatio();
- }
-
- return getSplitScreenAspectRatio();
- }
-
/**
* @return {@value true} if the resulting app is letterboxed in a way defined as thin.
*/
@@ -547,123 +472,9 @@ final class LetterboxUiController {
return !isHorizontalThinLetterboxed();
}
- float getSplitScreenAspectRatio() {
- // Getting the same aspect ratio that apps get in split screen.
- final DisplayArea displayArea = mActivityRecord.getDisplayArea();
- if (displayArea == null) {
- return getDefaultMinAspectRatioForUnresizableApps();
- }
- int dividerWindowWidth =
- getResources().getDimensionPixelSize(R.dimen.docked_stack_divider_thickness);
- int dividerInsets =
- getResources().getDimensionPixelSize(R.dimen.docked_stack_divider_insets);
- int dividerSize = dividerWindowWidth - dividerInsets * 2;
- final Rect bounds = new Rect(displayArea.getWindowConfiguration().getAppBounds());
- if (bounds.width() >= bounds.height()) {
- bounds.inset(/* dx */ dividerSize / 2, /* dy */ 0);
- bounds.right = bounds.centerX();
- } else {
- bounds.inset(/* dx */ 0, /* dy */ dividerSize / 2);
- bounds.bottom = bounds.centerY();
- }
- return computeAspectRatio(bounds);
- }
-
- /**
- * Whether we should enable users to resize the current app.
- */
- boolean shouldEnableUserAspectRatioSettings() {
- return getAppCompatOverrides().shouldEnableUserAspectRatioSettings();
- }
-
- /**
- * Whether we should apply the user aspect ratio override to the min aspect ratio for the
- * current app.
- */
- boolean shouldApplyUserMinAspectRatioOverride() {
- if (!shouldEnableUserAspectRatioSettings()) {
- return false;
- }
-
- mUserAspectRatio = getUserMinAspectRatioOverrideCode();
-
- return mUserAspectRatio != USER_MIN_ASPECT_RATIO_UNSET
- && mUserAspectRatio != USER_MIN_ASPECT_RATIO_APP_DEFAULT
- && mUserAspectRatio != USER_MIN_ASPECT_RATIO_FULLSCREEN;
- }
-
- boolean shouldApplyUserFullscreenOverride() {
- if (isUserFullscreenOverrideEnabled()) {
- mUserAspectRatio = getUserMinAspectRatioOverrideCode();
-
- return mUserAspectRatio == USER_MIN_ASPECT_RATIO_FULLSCREEN;
- }
-
- return false;
- }
-
- boolean isUserFullscreenOverrideEnabled() {
- return getAppCompatOverrides().isUserFullscreenOverrideEnabled();
- }
-
- boolean isSystemOverrideToFullscreenEnabled() {
- return getAppCompatOverrides().isSystemOverrideToFullscreenEnabled(mUserAspectRatio);
- }
-
- boolean hasFullscreenOverride() {
- // `mUserAspectRatio` is always initialized first in `shouldApplyUserFullscreenOverride()`.
- return shouldApplyUserFullscreenOverride() || isSystemOverrideToFullscreenEnabled();
- }
-
- float getUserMinAspectRatio() {
- switch (mUserAspectRatio) {
- case USER_MIN_ASPECT_RATIO_DISPLAY_SIZE:
- return getDisplaySizeMinAspectRatio();
- case USER_MIN_ASPECT_RATIO_SPLIT_SCREEN:
- return getSplitScreenAspectRatio();
- case USER_MIN_ASPECT_RATIO_16_9:
- return 16 / 9f;
- case USER_MIN_ASPECT_RATIO_4_3:
- return 4 / 3f;
- case USER_MIN_ASPECT_RATIO_3_2:
- return 3 / 2f;
- default:
- throw new AssertionError("Unexpected user min aspect ratio override: "
- + mUserAspectRatio);
- }
- }
-
- @VisibleForTesting
- int getUserMinAspectRatioOverrideCode() {
- try {
- return mActivityRecord.mAtmService.getPackageManager()
- .getUserMinAspectRatio(mActivityRecord.packageName, mActivityRecord.mUserId);
- } catch (RemoteException e) {
- Slog.w(TAG, "Exception thrown retrieving aspect ratio user override " + this, e);
- }
- return mUserAspectRatio;
- }
-
- private float getDisplaySizeMinAspectRatio() {
- final DisplayArea displayArea = mActivityRecord.getDisplayArea();
- if (displayArea == null) {
- return mActivityRecord.info.getMinAspectRatio();
- }
- final Rect bounds = new Rect(displayArea.getWindowConfiguration().getAppBounds());
- return computeAspectRatio(bounds);
- }
-
- private float getDefaultMinAspectRatio() {
- if (mActivityRecord.getDisplayArea() == null
- || !mLetterboxConfiguration
- .getIsDisplayAspectRatioEnabledForFixedOrientationLetterbox()) {
- return mLetterboxConfiguration.getFixedOrientationLetterboxAspectRatio();
- }
- return getDisplaySizeMinAspectRatio();
- }
-
- Resources getResources() {
- return mActivityRecord.mWmService.mContext.getResources();
+ boolean shouldOverrideMinAspectRatio() {
+ return mActivityRecord.mAppCompatController.getAppCompatAspectRatioOverrides()
+ .shouldOverrideMinAspectRatio();
}
@LetterboxConfiguration.LetterboxVerticalReachabilityPosition
@@ -1086,7 +897,7 @@ final class LetterboxUiController {
pw.println(prefix + " letterboxReason=" + getLetterboxReasonString(mainWin));
pw.println(prefix + " activityAspectRatio="
- + mActivityRecord.computeAspectRatio(mActivityRecord.getBounds()));
+ + AppCompatUtils.computeAspectRatio(mActivityRecord.getBounds()));
boolean shouldShowLetterboxUi = shouldShowLetterboxUi(mainWin);
pw.println(prefix + "shouldShowLetterboxUi=" + shouldShowLetterboxUi);
@@ -1145,13 +956,15 @@ final class LetterboxUiController {
if (mActivityRecord.inSizeCompatMode()) {
return "SIZE_COMPAT_MODE";
}
- if (mActivityRecord.isLetterboxedForFixedOrientationAndAspectRatio()) {
+ if (mActivityRecord.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio()) {
return "FIXED_ORIENTATION";
}
if (mainWin.isLetterboxedForDisplayCutout()) {
return "DISPLAY_CUTOUT";
}
- if (mActivityRecord.isLetterboxedForAspectRatioOnly()) {
+ if (mActivityRecord.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForAspectRatioOnly()) {
return "ASPECT_RATIO";
}
return "UNKNOWN_REASON";
diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java
index a8edaebd24a6..f8665c70c61d 100644
--- a/services/core/java/com/android/server/wm/RemoteAnimationController.java
+++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java
@@ -44,8 +44,8 @@ import android.view.SurfaceControl.Transaction;
import android.view.WindowManager;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.LogLevel;
import com.android.internal.protolog.ProtoLog;
+import com.android.internal.protolog.common.LogLevel;
import com.android.internal.util.FastPrintWriter;
import com.android.server.wm.SurfaceAnimator.AnimationType;
import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
@@ -53,7 +53,6 @@ import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
-import java.util.function.Consumer;
/**
* Helper class to run app animations in a remote process.
@@ -349,10 +348,6 @@ class RemoteAnimationController implements DeathRecipient {
} finally {
mIsFinishing = false;
}
- // Reset input for all activities when the remote animation is finished.
- final Consumer<ActivityRecord> updateActivities =
- activity -> activity.setDropInputForAnimation(false);
- mDisplayContent.forAllActivities(updateActivities);
}
setRunningRemoteAnimation(false);
ProtoLog.i(WM_DEBUG_REMOTE_ANIMATIONS, "Finishing remote animation");
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 79fec231d421..74f8a0683811 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -816,42 +816,30 @@ class Task extends TaskFragment {
}
}
- /** Convenience method to reparent a task to the top or bottom position of the root task. */
- boolean reparent(Task preferredRootTask, boolean toTop,
- @ReparentMoveRootTaskMode int moveRootTaskMode, boolean animate, boolean deferResume,
- String reason) {
- return reparent(preferredRootTask, toTop ? MAX_VALUE : 0, moveRootTaskMode, animate,
- deferResume, true /* schedulePictureInPictureModeChange */, reason);
- }
-
/**
* Reparents the task into a preferred root task, creating it if necessary.
*
* @param preferredRootTask the target root task to move this task
- * @param position the position to place this task in the new root task
+ * @param toTop top or bottom position to place this task in the target task
* @param animate whether or not we should wait for the new window created as a part of the
* reparenting to be drawn and animated in
* @param moveRootTaskMode whether or not to move the root task to the front always, only if
* it was previously focused & in front, or never
* @param deferResume whether or not to update the visibility of other tasks and root tasks
* that may have changed as a result of this reparenting
- * @param schedulePictureInPictureModeChange specifies whether or not to schedule the PiP mode
- * change. Callers may set this to false if they are explicitly scheduling PiP mode
- * changes themselves, like during the PiP animation
* @param reason the caller of this reparenting
* @return whether the task was reparented
*/
// TODO: Inspect all call sites and change to just changing windowing mode of the root task vs.
// re-parenting the task. Can only be done when we are no longer using static root task Ids.
- boolean reparent(Task preferredRootTask, int position,
+ boolean reparent(Task preferredRootTask, boolean toTop,
@ReparentMoveRootTaskMode int moveRootTaskMode, boolean animate, boolean deferResume,
- boolean schedulePictureInPictureModeChange, String reason) {
+ String reason) {
final ActivityTaskSupervisor supervisor = mTaskSupervisor;
final RootWindowContainer root = mRootWindowContainer;
- final WindowManagerService windowManager = mAtmService.mWindowManager;
final Task sourceRootTask = getRootTask();
final Task toRootTask = supervisor.getReparentTargetRootTask(this, preferredRootTask,
- position == MAX_VALUE);
+ toTop);
if (toRootTask == sourceRootTask) {
return false;
}
@@ -862,7 +850,6 @@ class Task extends TaskFragment {
final ActivityRecord topActivity = getTopNonFinishingActivity();
mAtmService.deferWindowLayout();
- boolean kept = true;
try {
final ActivityRecord r = topRunningActivityLocked();
final boolean wasFocused = r != null && root.isTopDisplayFocusedRootTask(sourceRootTask)
@@ -878,12 +865,7 @@ class Task extends TaskFragment {
|| (moveRootTaskMode == REPARENT_KEEP_ROOT_TASK_AT_FRONT
&& (wasFocused || wasFront));
- reparent(toRootTask, position, moveRootTaskToFront, reason);
-
- if (schedulePictureInPictureModeChange) {
- // Notify of picture-in-picture mode changes
- supervisor.scheduleUpdatePictureInPictureModeIfNeeded(this, sourceRootTask);
- }
+ reparent(toRootTask, toTop ? MAX_VALUE : 0, moveRootTaskToFront, reason);
// If the task had focus before (or we're requested to move focus), move focus to the
// new root task by moving the root task to the front.
@@ -3424,9 +3406,11 @@ class Task extends TaskFragment {
appCompatTaskInfo.topActivityLetterboxWidth = TaskInfo.PROPERTY_VALUE_UNSET;
appCompatTaskInfo.topActivityLetterboxHeight = TaskInfo.PROPERTY_VALUE_UNSET;
appCompatTaskInfo.isUserFullscreenOverrideEnabled = top != null
- && top.mLetterboxUiController.shouldApplyUserFullscreenOverride();
+ && top.mAppCompatController.getAppCompatAspectRatioOverrides()
+ .shouldApplyUserFullscreenOverride();
appCompatTaskInfo.isSystemFullscreenOverrideEnabled = top != null
- && top.mLetterboxUiController.isSystemOverrideToFullscreenEnabled();
+ && top.mAppCompatController.getAppCompatAspectRatioOverrides()
+ .isSystemOverrideToFullscreenEnabled();
appCompatTaskInfo.isFromLetterboxDoubleTap = top != null
&& top.mLetterboxUiController.isFromDoubleTap();
if (top != null) {
@@ -3460,7 +3444,8 @@ class Task extends TaskFragment {
}
appCompatTaskInfo.topActivityEligibleForUserAspectRatioButton = top != null
&& !appCompatTaskInfo.topActivityInSizeCompat
- && top.mLetterboxUiController.shouldEnableUserAspectRatioSettings()
+ && top.mAppCompatController.getAppCompatAspectRatioOverrides()
+ .shouldEnableUserAspectRatioSettings()
&& !info.isTopActivityTransparent;
appCompatTaskInfo.topActivityBoundsLetterboxed = top != null && top.areBoundsLetterboxed();
appCompatTaskInfo.cameraCompatTaskInfo.freeformCameraCompatMode = top == null
diff --git a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
index b6b6cf2dc430..439c7bb4050b 100644
--- a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
@@ -46,7 +46,6 @@ import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Slog;
import android.util.SparseArray;
-import android.view.RemoteAnimationDefinition;
import android.view.WindowManager;
import android.window.ITaskFragmentOrganizer;
import android.window.ITaskFragmentOrganizerController;
@@ -58,8 +57,8 @@ import android.window.TaskFragmentTransaction;
import android.window.WindowContainerTransaction;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.ProtoLogGroup;
import com.android.internal.protolog.ProtoLog;
+import com.android.internal.protolog.ProtoLogGroup;
import com.android.window.flags.Flags;
import java.lang.annotation.Retention;
@@ -146,13 +145,6 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
private final boolean mIsSystemOrganizer;
/**
- * {@link RemoteAnimationDefinition} for embedded activities transition animation that is
- * organized by this organizer.
- */
- @Nullable
- private RemoteAnimationDefinition mRemoteAnimationDefinition;
-
- /**
* Map from {@link TaskFragmentTransaction#getTransactionToken()} to the
* {@link Transition#getSyncId()} that has been deferred. {@link TransitionController} will
* wait until the organizer finished handling the {@link TaskFragmentTransaction}.
@@ -533,50 +525,6 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
}
@Override
- public void registerRemoteAnimations(@NonNull ITaskFragmentOrganizer organizer,
- @NonNull RemoteAnimationDefinition definition) {
- final int pid = Binder.getCallingPid();
- final int uid = Binder.getCallingUid();
- synchronized (mGlobalLock) {
- ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER,
- "Register remote animations for organizer=%s uid=%d pid=%d",
- organizer.asBinder(), uid, pid);
- final TaskFragmentOrganizerState organizerState =
- mTaskFragmentOrganizerState.get(organizer.asBinder());
- if (organizerState == null) {
- throw new IllegalStateException("The organizer hasn't been registered.");
- }
- if (organizerState.mRemoteAnimationDefinition != null) {
- throw new IllegalStateException(
- "The organizer has already registered remote animations="
- + organizerState.mRemoteAnimationDefinition);
- }
-
- definition.setCallingPidUid(pid, uid);
- organizerState.mRemoteAnimationDefinition = definition;
- }
- }
-
- @Override
- public void unregisterRemoteAnimations(@NonNull ITaskFragmentOrganizer organizer) {
- final int pid = Binder.getCallingPid();
- final long uid = Binder.getCallingUid();
- synchronized (mGlobalLock) {
- ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER,
- "Unregister remote animations for organizer=%s uid=%d pid=%d",
- organizer.asBinder(), uid, pid);
- final TaskFragmentOrganizerState organizerState =
- mTaskFragmentOrganizerState.get(organizer.asBinder());
- if (organizerState == null) {
- Slog.e(TAG, "The organizer hasn't been registered.");
- return;
- }
-
- organizerState.mRemoteAnimationDefinition = null;
- }
- }
-
- @Override
public void onTransactionHandled(@NonNull IBinder transactionToken,
@NonNull WindowContainerTransaction wct,
@WindowManager.TransitionType int transitionType, boolean shouldApplyIndependently) {
@@ -617,25 +565,6 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
}
}
- /**
- * Gets the {@link RemoteAnimationDefinition} set on the given organizer if exists. Returns
- * {@code null} if it doesn't.
- */
- @Nullable
- public RemoteAnimationDefinition getRemoteAnimationDefinition(
- @NonNull ITaskFragmentOrganizer organizer) {
- synchronized (mGlobalLock) {
- final TaskFragmentOrganizerState organizerState =
- mTaskFragmentOrganizerState.get(organizer.asBinder());
- if (organizerState == null) {
- Slog.e(TAG, "TaskFragmentOrganizer has been unregistered or died when trying"
- + " to play animation on its organized windows.");
- return null;
- }
- return organizerState.mRemoteAnimationDefinition;
- }
- }
-
int getTaskFragmentOrganizerUid(@NonNull ITaskFragmentOrganizer organizer) {
final TaskFragmentOrganizerState state = validateAndGetState(organizer);
return state.mOrganizerUid;
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 47af6fc0a6c7..2a3e94544aea 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -2757,12 +2757,19 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
return out;
}
+ // Get the animation theme from the top-most application window
+ // when Flags.customAnimationsBehindTranslucent() is false.
final AnimationOptions animOptionsForActivityTransition =
calculateAnimationOptionsForActivityTransition(type, sortedTargets);
+
if (!Flags.moveAnimationOptionsToChange() && animOptionsForActivityTransition != null) {
out.setAnimationOptions(animOptionsForActivityTransition);
}
+ // Store the animation options of the topmost non-translucent change
+ // (Used when Flags.customAnimationsBehindTranslucent() is true)
+ AnimationOptions activityAboveAnimationOptions = null;
+
final ArraySet<WindowContainer> occludedAtEndContainers = new ArraySet<>();
// Convert all the resolved ChangeInfos into TransactionInfo.Change objects in order.
final int count = sortedTargets.size();
@@ -2881,9 +2888,26 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
change.setBackgroundColor(ColorUtils.setAlphaComponent(backgroundColor, 255));
}
- AnimationOptions animOptions = null;
+ // Calculate the animation options for this change
if (Flags.moveAnimationOptionsToChange()) {
- if (activityRecord != null && animOptionsForActivityTransition != null) {
+ AnimationOptions animOptions = null;
+ if (Flags.customAnimationsBehindTranslucent() && activityRecord != null) {
+ if (activityAboveAnimationOptions != null) {
+ // Inherit the options from one of the changes on top of this
+ animOptions = activityAboveAnimationOptions;
+ } else {
+ // Create the options based on this change's custom animations and layout
+ // parameters
+ animOptions = getOptions(activityRecord /* customAnimActivity */,
+ activityRecord /* animLpActivity */);
+ if (!change.hasFlags(FLAG_TRANSLUCENT)) {
+ // If this change is not translucent, its options are going to be
+ // inherited by the changes below
+ activityAboveAnimationOptions = animOptions;
+ }
+ }
+ } else if (activityRecord != null && animOptionsForActivityTransition != null) {
+ // Use the same options from the top activity for all the activities
animOptions = animOptionsForActivityTransition;
} else if (Flags.activityEmbeddingOverlayPresentationFlag()
&& isEmbeddedTaskFragment) {
@@ -2931,25 +2955,42 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
@Nullable
private static AnimationOptions calculateAnimationOptionsForActivityTransition(
@TransitionType int type, @NonNull ArrayList<ChangeInfo> sortedTargets) {
- TransitionInfo.AnimationOptions animOptions = null;
-
- // Check if the top-most app is an activity (ie. activity->activity). If so, make sure
- // to honor its custom transition options.
WindowContainer<?> topApp = null;
for (int i = 0; i < sortedTargets.size(); i++) {
- if (isWallpaper(sortedTargets.get(i).mContainer)) continue;
- topApp = sortedTargets.get(i).mContainer;
- break;
+ if (!isWallpaper(sortedTargets.get(i).mContainer)) {
+ topApp = sortedTargets.get(i).mContainer;
+ break;
+ }
}
- if (topApp.asActivityRecord() != null) {
- final ActivityRecord topActivity = topApp.asActivityRecord();
- animOptions = addCustomActivityTransition(topActivity, true/* open */,
- null /* animOptions */);
- animOptions = addCustomActivityTransition(topActivity, false/* open */,
+ ActivityRecord animLpActivity = findAnimLayoutParamsActivityRecord(type, sortedTargets);
+ return getOptions(topApp.asActivityRecord() /* customAnimActivity */,
+ animLpActivity /* animLpActivity */);
+ }
+
+ /**
+ * Updates and returns animOptions with the layout parameters of animLpActivity
+ * @param customAnimActivity the activity that drives the custom animation options
+ * @param animLpActivity the activity that drives the animation options with its layout
+ * parameters
+ * @return the options extracted from the provided activities
+ */
+ @Nullable
+ private static AnimationOptions getOptions(@Nullable ActivityRecord customAnimActivity,
+ @Nullable ActivityRecord animLpActivity) {
+ AnimationOptions animOptions = null;
+ // Custom
+ if (customAnimActivity != null) {
+ animOptions = addCustomActivityTransition(customAnimActivity, true /* open */,
+ animOptions);
+ animOptions = addCustomActivityTransition(customAnimActivity, false /* open */,
animOptions);
}
- final WindowManager.LayoutParams animLp =
- getLayoutParamsForAnimationsStyle(type, sortedTargets);
+
+ // Layout parameters
+ final WindowState mainWindow = animLpActivity != null
+ ? animLpActivity.findMainWindow() : null;
+ final WindowManager.LayoutParams animLp = mainWindow != null ? mainWindow.mAttrs : null;
+
if (animLp != null && animLp.type != TYPE_APPLICATION_STARTING
&& animLp.windowAnimations != 0) {
// Don't send animation options if no windowAnimations have been set or if the we
@@ -3087,10 +3128,9 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
return ancestor;
}
- private static WindowManager.LayoutParams getLayoutParamsForAnimationsStyle(int type,
- ArrayList<ChangeInfo> sortedTargets) {
- // Find the layout params of the top-most application window that is part of the
- // transition, which is what will control the animation theme.
+ @Nullable
+ private static ActivityRecord findAnimLayoutParamsActivityRecord(
+ @TransitionType int transit, @NonNull List<ChangeInfo> sortedTargets) {
final ArraySet<Integer> activityTypes = new ArraySet<>();
final int targetCount = sortedTargets.size();
for (int i = 0; i < targetCount; ++i) {
@@ -3110,16 +3150,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
// activity through the layout parameter animation style.
return null;
}
- final ActivityRecord animLpActivity =
- findAnimLayoutParamsActivityRecord(sortedTargets, type, activityTypes);
- final WindowState mainWindow = animLpActivity != null
- ? animLpActivity.findMainWindow() : null;
- return mainWindow != null ? mainWindow.mAttrs : null;
- }
- private static ActivityRecord findAnimLayoutParamsActivityRecord(
- List<ChangeInfo> sortedTargets,
- @TransitionType int transit, ArraySet<Integer> activityTypes) {
// Remote animations always win, but fullscreen windows override non-fullscreen windows.
ActivityRecord result = lookForTopWindowWithFilter(sortedTargets,
w -> w.getRemoteAnimationDefinition() != null
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 1d02f1c133f6..eb1a80b74b76 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -117,6 +117,7 @@ import com.android.server.wm.SurfaceAnimator.Animatable;
import com.android.server.wm.SurfaceAnimator.AnimationType;
import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
import com.android.server.wm.utils.AlwaysTruePredicate;
+import com.android.window.flags.Flags;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
@@ -458,6 +459,9 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
source.setFrame(provider.getArbitraryRectangle())
.updateSideHint(getBounds())
.setBoundingRects(provider.getBoundingRects());
+ if (Flags.enableCaptionCompatInsetForceConsumption()) {
+ source.setFlags(provider.getFlags());
+ }
mLocalInsetsSources.put(id, source);
mDisplayContent.getInsetsStateController().updateAboveInsetsState(true);
}
@@ -2579,8 +2583,12 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
// Containers don't belong to the same hierarchy???
if (commonAncestor == null) {
- throw new IllegalArgumentException("No in the same hierarchy this="
- + thisParentChain + " other=" + otherParentChain);
+ final int thisZ = getPrefixOrderIndex();
+ final int otherZ = other.getPrefixOrderIndex();
+ Slog.w(TAG, "Compare not in the same hierarchy this="
+ + thisParentChain + " thisZ=" + thisZ + " other="
+ + otherParentChain + " otherZ=" + otherZ);
+ return Integer.compare(thisZ, otherZ);
}
// Children are always considered greater than their parents, so if one of the containers
diff --git a/services/core/java/com/android/server/wm/WindowManagerFlags.java b/services/core/java/com/android/server/wm/WindowManagerFlags.java
index 294733e85fbd..f3e6a184ce45 100644
--- a/services/core/java/com/android/server/wm/WindowManagerFlags.java
+++ b/services/core/java/com/android/server/wm/WindowManagerFlags.java
@@ -50,5 +50,8 @@ class WindowManagerFlags {
final boolean mInsetsDecoupledConfiguration = Flags.insetsDecoupledConfiguration();
+ final boolean mRespectNonTopVisibleFixedOrientation =
+ Flags.respectNonTopVisibleFixedOrientation();
+
/* End Available Flags */
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 803312214fc3..700c069a51c3 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -283,6 +283,7 @@ import android.view.InsetsFrameProvider;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
import android.view.KeyEvent;
+import android.view.KeyboardShortcutGroup;
import android.view.MagnificationSpec;
import android.view.RemoteAnimationAdapter;
import android.view.ScrollCaptureResponse;
@@ -334,8 +335,8 @@ import com.android.internal.policy.IKeyguardLockedStateListener;
import com.android.internal.policy.IShortcutService;
import com.android.internal.policy.KeyInterceptionInfo;
import com.android.internal.protolog.LegacyProtoLogImpl;
-import com.android.internal.protolog.ProtoLogGroup;
import com.android.internal.protolog.ProtoLog;
+import com.android.internal.protolog.ProtoLogGroup;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.FrameworkStatsLog;
@@ -7440,6 +7441,16 @@ public class WindowManagerService extends IWindowManager.Stub
}
@Override
+ public KeyboardShortcutGroup getApplicationLaunchKeyboardShortcuts(int deviceId) {
+ long token = Binder.clearCallingIdentity();
+ try {
+ return mPolicy.getApplicationLaunchKeyboardShortcuts(deviceId);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
public void requestAppKeyboardShortcuts(IResultReceiver receiver, int deviceId) {
enforceRegisterWindowManagerListenersPermission("requestAppKeyboardShortcuts");
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 60d3e787cac4..bbd9c0a820ef 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -1655,6 +1655,22 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
// Otherwise if other places send wpc.getConfiguration() to client, the configuration may
// be ignored due to the seq is older.
resolvedConfig.seq = newParentConfig.seq;
+
+ if (mConfigActivityRecord != null) {
+ // Let the activity decide whether to apply the size override.
+ return;
+ }
+ final DisplayContent displayContent = mAtm.mWindowManager != null
+ ? mAtm.mWindowManager.getDefaultDisplayContentLocked()
+ : null;
+ applySizeOverrideIfNeeded(
+ displayContent,
+ mInfo,
+ newParentConfig,
+ resolvedConfig,
+ false /* optOutEdgeToEdge */,
+ false /* hasFixedRotationTransform */,
+ false /* hasCompatDisplayInsets */);
}
void dispatchConfiguration(@NonNull Configuration config) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index de73e6cfad12..228eb7626e7c 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1101,7 +1101,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
mPolicy = mWmService.mPolicy;
mContext = mWmService.mContext;
mForceSeamlesslyRotate = token.mRoundedCornerOverlay;
- mLastReportedActivityWindowInfo = Flags.activityWindowInfoFlag() && mActivityRecord != null
+ mLastReportedActivityWindowInfo = mActivityRecord != null
? new ActivityWindowInfo()
: null;
mInputWindowHandle = new InputWindowHandleWrapper(new InputWindowHandle(
diff --git a/services/core/java/com/android/server/wm/WindowTracing.java b/services/core/java/com/android/server/wm/WindowTracing.java
index ba5323ee1f8f..21f7eca5627a 100644
--- a/services/core/java/com/android/server/wm/WindowTracing.java
+++ b/services/core/java/com/android/server/wm/WindowTracing.java
@@ -18,89 +18,52 @@ package com.android.server.wm;
import static android.os.Build.IS_USER;
-import static com.android.server.wm.WindowManagerTraceFileProto.ENTRY;
-import static com.android.server.wm.WindowManagerTraceFileProto.MAGIC_NUMBER;
-import static com.android.server.wm.WindowManagerTraceFileProto.MAGIC_NUMBER_H;
-import static com.android.server.wm.WindowManagerTraceFileProto.MAGIC_NUMBER_L;
-import static com.android.server.wm.WindowManagerTraceFileProto.REAL_TO_ELAPSED_TIME_OFFSET_NANOS;
import static com.android.server.wm.WindowManagerTraceProto.ELAPSED_REALTIME_NANOS;
import static com.android.server.wm.WindowManagerTraceProto.WHERE;
import static com.android.server.wm.WindowManagerTraceProto.WINDOW_MANAGER_SERVICE;
import android.annotation.Nullable;
import android.os.ShellCommand;
-import android.os.SystemClock;
import android.os.Trace;
import android.util.Log;
import android.util.proto.ProtoOutputStream;
import android.view.Choreographer;
import com.android.internal.protolog.LegacyProtoLogImpl;
-import com.android.internal.protolog.common.IProtoLog;
import com.android.internal.protolog.ProtoLog;
-import com.android.internal.util.TraceBuffer;
-import java.io.File;
-import java.io.IOException;
import java.io.PrintWriter;
-import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
/**
- * A class that allows window manager to dump its state continuously to a trace file, such that a
+ * A class that allows window manager to dump its state continuously, such that a
* time series of window manager state can be analyzed after the fact.
*/
-class WindowTracing {
-
- /**
- * Maximum buffer size, currently defined as 5 MB
- * Size was experimentally defined to fit between 100 to 150 elements.
- */
- private static final int BUFFER_CAPACITY_CRITICAL = 5120 * 1024; // 5 MB
- private static final int BUFFER_CAPACITY_TRIM = 10240 * 1024; // 10 MB
- private static final int BUFFER_CAPACITY_ALL = 20480 * 1024; // 20 MB
- static final String WINSCOPE_EXT = ".winscope";
- private static final String TRACE_FILENAME = "/data/misc/wmtrace/wm_trace" + WINSCOPE_EXT;
- private static final String TAG = "WindowTracing";
- private static final long MAGIC_NUMBER_VALUE = ((long) MAGIC_NUMBER_H << 32) | MAGIC_NUMBER_L;
+abstract class WindowTracing {
+ protected static final String TAG = "WindowTracing";
+ protected static final String WHERE_START_TRACING = "trace.enable";
+ protected static final String WHERE_ON_FRAME = "onFrame";
private final WindowManagerService mService;
private final Choreographer mChoreographer;
private final WindowManagerGlobalLock mGlobalLock;
- private final Object mEnabledLock = new Object();
- private final File mTraceFile;
- private final TraceBuffer mBuffer;
private final Choreographer.FrameCallback mFrameCallback = (frameTimeNanos) ->
- log("onFrame" /* where */);
+ log(WHERE_ON_FRAME);
- private @WindowTraceLogLevel int mLogLevel = WindowTraceLogLevel.TRIM;
- private boolean mLogOnFrame = false;
- private boolean mEnabled;
- private volatile boolean mEnabledLockFree;
- private boolean mScheduled;
+ private AtomicBoolean mScheduled = new AtomicBoolean(false);
- private final IProtoLog mProtoLog;
static WindowTracing createDefaultAndStartLooper(WindowManagerService service,
Choreographer choreographer) {
- File file = new File(TRACE_FILENAME);
- return new WindowTracing(file, service, choreographer, BUFFER_CAPACITY_TRIM);
+ return new WindowTracingLegacy(service, choreographer);
}
- private WindowTracing(File file, WindowManagerService service, Choreographer choreographer,
- int bufferCapacity) {
- this(file, service, choreographer, service.mGlobalLock, bufferCapacity);
- }
-
- WindowTracing(File file, WindowManagerService service, Choreographer choreographer,
- WindowManagerGlobalLock globalLock, int bufferCapacity) {
+ protected WindowTracing(WindowManagerService service, Choreographer choreographer,
+ WindowManagerGlobalLock globalLock) {
mChoreographer = choreographer;
mService = service;
mGlobalLock = globalLock;
- mTraceFile = file;
- mBuffer = new TraceBuffer(bufferCapacity);
- setLogLevel(WindowTraceLogLevel.TRIM, null /* pw */);
- mProtoLog = ProtoLog.getSingleInstance();
}
void startTrace(@Nullable PrintWriter pw) {
@@ -108,44 +71,29 @@ class WindowTracing {
logAndPrintln(pw, "Error: Tracing is not supported on user builds.");
return;
}
- synchronized (mEnabledLock) {
- if (!android.tracing.Flags.perfettoProtologTracing()) {
- ((LegacyProtoLogImpl) ProtoLog.getSingleInstance()).startProtoLog(pw);
- }
- logAndPrintln(pw, "Start tracing to " + mTraceFile + ".");
- mBuffer.resetBuffer();
- mEnabled = mEnabledLockFree = true;
+ if (!android.tracing.Flags.perfettoProtologTracing()) {
+ ((LegacyProtoLogImpl) ProtoLog.getSingleInstance()).startProtoLog(pw);
}
- log("trace.enable");
+ startTraceInternal(pw);
}
- /**
- * Stops the trace and write the current buffer to disk
- * @param pw Print writer
- */
void stopTrace(@Nullable PrintWriter pw) {
if (IS_USER) {
logAndPrintln(pw, "Error: Tracing is not supported on user builds.");
return;
}
- synchronized (mEnabledLock) {
- logAndPrintln(pw, "Stop tracing to " + mTraceFile + ". Waiting for traces to flush.");
- mEnabled = mEnabledLockFree = false;
-
- if (mEnabled) {
- logAndPrintln(pw, "ERROR: tracing was re-enabled while waiting for flush.");
- throw new IllegalStateException("tracing enabled while waiting for flush.");
- }
- writeTraceToFileLocked();
- logAndPrintln(pw, "Trace written to " + mTraceFile + ".");
- }
if (!android.tracing.Flags.perfettoProtologTracing()) {
((LegacyProtoLogImpl) ProtoLog.getSingleInstance()).stopProtoLog(pw, true);
}
+ stopTraceInternal(pw);
}
/**
- * Stops the trace and write the current buffer to disk then restart, if it's already running.
+ * If legacy tracing is enabled (either WM or ProtoLog):
+ * 1. Stop tracing
+ * 2. Write trace to disk (to be picked by dumpstate)
+ * 3. Restart tracing
+ *
* @param pw Print writer
*/
void saveForBugreport(@Nullable PrintWriter pw) {
@@ -153,143 +101,24 @@ class WindowTracing {
logAndPrintln(pw, "Error: Tracing is not supported on user builds.");
return;
}
- synchronized (mEnabledLock) {
- if (!mEnabled) {
- return;
- }
- mEnabled = mEnabledLockFree = false;
- logAndPrintln(pw, "Stop tracing to " + mTraceFile + ". Waiting for traces to flush.");
- writeTraceToFileLocked();
- logAndPrintln(pw, "Trace written to " + mTraceFile + ".");
- if (!android.tracing.Flags.perfettoProtologTracing()) {
- ((LegacyProtoLogImpl) mProtoLog).stopProtoLog(pw, true);
- }
- logAndPrintln(pw, "Start tracing to " + mTraceFile + ".");
- mBuffer.resetBuffer();
- mEnabled = mEnabledLockFree = true;
- if (!android.tracing.Flags.perfettoProtologTracing()) {
- ((LegacyProtoLogImpl) mProtoLog).startProtoLog(pw);
- }
- }
- }
-
- private void setLogLevel(@WindowTraceLogLevel int logLevel, PrintWriter pw) {
- logAndPrintln(pw, "Setting window tracing log level to " + logLevel);
- mLogLevel = logLevel;
-
- switch (logLevel) {
- case WindowTraceLogLevel.ALL: {
- setBufferCapacity(BUFFER_CAPACITY_ALL, pw);
- break;
- }
- case WindowTraceLogLevel.TRIM: {
- setBufferCapacity(BUFFER_CAPACITY_TRIM, pw);
- break;
- }
- case WindowTraceLogLevel.CRITICAL: {
- setBufferCapacity(BUFFER_CAPACITY_CRITICAL, pw);
- break;
- }
- }
- }
-
- private void setLogFrequency(boolean onFrame, PrintWriter pw) {
- logAndPrintln(pw, "Setting window tracing log frequency to "
- + ((onFrame) ? "frame" : "transaction"));
- mLogOnFrame = onFrame;
- }
-
- private void setBufferCapacity(int capacity, PrintWriter pw) {
- logAndPrintln(pw, "Setting window tracing buffer capacity to " + capacity + "bytes");
- mBuffer.setCapacity(capacity);
- }
-
- boolean isEnabled() {
- return mEnabledLockFree;
- }
-
- int onShellCommand(ShellCommand shell) {
- PrintWriter pw = shell.getOutPrintWriter();
- String cmd = shell.getNextArgRequired();
- switch (cmd) {
- case "start":
- startTrace(pw);
- return 0;
- case "stop":
- stopTrace(pw);
- return 0;
- case "save-for-bugreport":
- saveForBugreport(pw);
- return 0;
- case "status":
- logAndPrintln(pw, getStatus());
- return 0;
- case "frame":
- setLogFrequency(true /* onFrame */, pw);
- mBuffer.resetBuffer();
- return 0;
- case "transaction":
- setLogFrequency(false /* onFrame */, pw);
- mBuffer.resetBuffer();
- return 0;
- case "level":
- String logLevelStr = shell.getNextArgRequired().toLowerCase();
- switch (logLevelStr) {
- case "all": {
- setLogLevel(WindowTraceLogLevel.ALL, pw);
- break;
- }
- case "trim": {
- setLogLevel(WindowTraceLogLevel.TRIM, pw);
- break;
- }
- case "critical": {
- setLogLevel(WindowTraceLogLevel.CRITICAL, pw);
- break;
- }
- default: {
- setLogLevel(WindowTraceLogLevel.TRIM, pw);
- break;
- }
- }
- mBuffer.resetBuffer();
- return 0;
- case "size":
- setBufferCapacity(Integer.parseInt(shell.getNextArgRequired()) * 1024, pw);
- mBuffer.resetBuffer();
- return 0;
- default:
- pw.println("Unknown command: " + cmd);
- pw.println("Window manager trace options:");
- pw.println(" start: Start logging");
- pw.println(" stop: Stop logging");
- pw.println(" save-for-bugreport: Save logging data to file if it's running.");
- pw.println(" frame: Log trace once per frame");
- pw.println(" transaction: Log each transaction");
- pw.println(" size: Set the maximum log size (in KB)");
- pw.println(" status: Print trace status");
- pw.println(" level [lvl]: Set the log level between");
- pw.println(" lvl may be one of:");
- pw.println(" critical: Only visible windows with reduced information");
- pw.println(" trim: All windows with reduced");
- pw.println(" all: All window and information");
- return -1;
+ if (!android.tracing.Flags.perfettoProtologTracing()
+ && ProtoLog.getSingleInstance().isProtoEnabled()) {
+ ((LegacyProtoLogImpl) ProtoLog.getSingleInstance()).stopProtoLog(pw, true);
+ ((LegacyProtoLogImpl) ProtoLog.getSingleInstance()).startProtoLog(pw);
}
+ saveForBugreportInternal(pw);
}
- String getStatus() {
- return "Status: "
- + ((isEnabled()) ? "Enabled" : "Disabled")
- + "\n"
- + "Log level: "
- + mLogLevel
- + "\n"
- + mBuffer.getStatus();
- }
+ abstract void setLogLevel(@WindowTraceLogLevel int logLevel, PrintWriter pw);
+ abstract void setLogFrequency(boolean onFrame, PrintWriter pw);
+ abstract void setBufferCapacity(int capacity, PrintWriter pw);
+ abstract boolean isEnabled();
+ abstract int onShellCommand(ShellCommand shell);
+ abstract String getStatus();
/**
* If tracing is enabled, log the current state or schedule the next frame to be logged,
- * according to {@link #mLogOnFrame}.
+ * according to the configuration in the derived tracing class.
*
* @param where Logging point descriptor
*/
@@ -298,59 +127,63 @@ class WindowTracing {
return;
}
- if (mLogOnFrame) {
- schedule();
- } else {
+ if (shouldLogOnTransaction()) {
log(where);
}
+
+ if (shouldLogOnFrame()) {
+ schedule();
+ }
}
/**
* Schedule the log to trace the next frame
*/
private void schedule() {
- if (mScheduled) {
+ if (!mScheduled.compareAndSet(false, true)) {
return;
}
- mScheduled = true;
mChoreographer.postFrameCallback(mFrameCallback);
}
/**
- * Write the current frame to the buffer
+ * Write the current frame to proto
*
+ * @param os Proto stream buffer
+ * @param logLevel Log level
* @param where Logging point descriptor
+ * @param elapsedRealtimeNanos Timestamp
*/
- private void log(String where) {
+ protected void dumpToProto(ProtoOutputStream os, @WindowTraceLogLevel int logLevel,
+ String where, long elapsedRealtimeNanos) {
Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "traceStateLocked");
try {
- ProtoOutputStream os = new ProtoOutputStream();
- long tokenOuter = os.start(ENTRY);
- os.write(ELAPSED_REALTIME_NANOS, SystemClock.elapsedRealtimeNanos());
+ os.write(ELAPSED_REALTIME_NANOS, elapsedRealtimeNanos);
os.write(WHERE, where);
- long tokenInner = os.start(WINDOW_MANAGER_SERVICE);
+ long token = os.start(WINDOW_MANAGER_SERVICE);
synchronized (mGlobalLock) {
Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "dumpDebugLocked");
try {
- mService.dumpDebugLocked(os, mLogLevel);
+ mService.dumpDebugLocked(os, logLevel);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
}
}
- os.end(tokenInner);
- os.end(tokenOuter);
- mBuffer.add(os);
- mScheduled = false;
+ os.end(token);
} catch (Exception e) {
Log.wtf(TAG, "Exception while tracing state", e);
} finally {
+ boolean isOnFrameLogEvent = where == WHERE_ON_FRAME;
+ if (isOnFrameLogEvent) {
+ mScheduled.set(false);
+ }
Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
}
}
- private void logAndPrintln(@Nullable PrintWriter pw, String msg) {
+ protected void logAndPrintln(@Nullable PrintWriter pw, String msg) {
Log.i(TAG, msg);
if (pw != null) {
pw.println(msg);
@@ -358,24 +191,10 @@ class WindowTracing {
}
}
- /**
- * Writes the trace buffer to disk. This method has no internal synchronization and should be
- * externally synchronized
- */
- private void writeTraceToFileLocked() {
- try {
- Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "writeTraceToFileLocked");
- ProtoOutputStream proto = new ProtoOutputStream();
- proto.write(MAGIC_NUMBER, MAGIC_NUMBER_VALUE);
- long timeOffsetNs =
- TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis())
- - SystemClock.elapsedRealtimeNanos();
- proto.write(REAL_TO_ELAPSED_TIME_OFFSET_NANOS, timeOffsetNs);
- mBuffer.writeTraceToFile(mTraceFile, proto);
- } catch (IOException e) {
- Log.e(TAG, "Unable to write buffer to file", e);
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
- }
- }
+ protected abstract void startTraceInternal(@Nullable PrintWriter pw);
+ protected abstract void stopTraceInternal(@Nullable PrintWriter pw);
+ protected abstract void saveForBugreportInternal(@Nullable PrintWriter pw);
+ protected abstract void log(String where);
+ protected abstract boolean shouldLogOnFrame();
+ protected abstract boolean shouldLogOnTransaction();
}
diff --git a/services/core/java/com/android/server/wm/WindowTracingLegacy.java b/services/core/java/com/android/server/wm/WindowTracingLegacy.java
new file mode 100644
index 000000000000..7a36707fd95a
--- /dev/null
+++ b/services/core/java/com/android/server/wm/WindowTracingLegacy.java
@@ -0,0 +1,276 @@
+/*
+ * 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.wm;
+
+import static com.android.server.wm.WindowManagerTraceFileProto.ENTRY;
+import static com.android.server.wm.WindowManagerTraceFileProto.MAGIC_NUMBER;
+import static com.android.server.wm.WindowManagerTraceFileProto.MAGIC_NUMBER_H;
+import static com.android.server.wm.WindowManagerTraceFileProto.MAGIC_NUMBER_L;
+import static com.android.server.wm.WindowManagerTraceFileProto.REAL_TO_ELAPSED_TIME_OFFSET_NANOS;
+
+import android.annotation.Nullable;
+import android.os.ShellCommand;
+import android.os.SystemClock;
+import android.os.Trace;
+import android.util.Log;
+import android.util.proto.ProtoOutputStream;
+import android.view.Choreographer;
+
+import com.android.internal.util.TraceBuffer;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.concurrent.TimeUnit;
+
+class WindowTracingLegacy extends WindowTracing {
+
+ /**
+ * Maximum buffer size, currently defined as 5 MB
+ * Size was experimentally defined to fit between 100 to 150 elements.
+ */
+ private static final int BUFFER_CAPACITY_CRITICAL = 5120 * 1024; // 5 MB
+ private static final int BUFFER_CAPACITY_TRIM = 10240 * 1024; // 10 MB
+ private static final int BUFFER_CAPACITY_ALL = 20480 * 1024; // 20 MB
+ static final String WINSCOPE_EXT = ".winscope";
+ private static final String TRACE_FILENAME = "/data/misc/wmtrace/wm_trace" + WINSCOPE_EXT;
+ private static final String TAG = "WindowTracing";
+ private static final long MAGIC_NUMBER_VALUE = ((long) MAGIC_NUMBER_H << 32) | MAGIC_NUMBER_L;
+
+ private final Object mEnabledLock = new Object();
+ private final File mTraceFile;
+ private final TraceBuffer mBuffer;
+
+ private boolean mEnabled;
+ private volatile boolean mEnabledLockFree;
+
+ protected @WindowTraceLogLevel int mLogLevel = WindowTraceLogLevel.TRIM;
+ protected boolean mLogOnFrame = false;
+
+ WindowTracingLegacy(WindowManagerService service, Choreographer choreographer) {
+ this(new File(TRACE_FILENAME), service, choreographer,
+ service.mGlobalLock, BUFFER_CAPACITY_TRIM);
+ }
+
+ WindowTracingLegacy(File traceFile, WindowManagerService service, Choreographer choreographer,
+ WindowManagerGlobalLock globalLock, int bufferSize) {
+ super(service, choreographer, globalLock);
+ mTraceFile = traceFile;
+ mBuffer = new TraceBuffer(bufferSize);
+ }
+
+ @Override
+ void setLogLevel(@WindowTraceLogLevel int logLevel, PrintWriter pw) {
+ logAndPrintln(pw, "Setting window tracing log level to " + logLevel);
+ mLogLevel = logLevel;
+
+ switch (logLevel) {
+ case WindowTraceLogLevel.ALL: {
+ setBufferCapacity(BUFFER_CAPACITY_ALL, pw);
+ break;
+ }
+ case WindowTraceLogLevel.TRIM: {
+ setBufferCapacity(BUFFER_CAPACITY_TRIM, pw);
+ break;
+ }
+ case WindowTraceLogLevel.CRITICAL: {
+ setBufferCapacity(BUFFER_CAPACITY_CRITICAL, pw);
+ break;
+ }
+ }
+ }
+
+ @Override
+ void setLogFrequency(boolean onFrame, PrintWriter pw) {
+ logAndPrintln(pw, "Setting window tracing log frequency to "
+ + ((onFrame) ? "frame" : "transaction"));
+ mLogOnFrame = onFrame;
+ }
+
+ @Override
+ void setBufferCapacity(int capacity, PrintWriter pw) {
+ logAndPrintln(pw, "Setting window tracing buffer capacity to " + capacity + "bytes");
+ mBuffer.setCapacity(capacity);
+ }
+
+ @Override
+ boolean isEnabled() {
+ return mEnabledLockFree;
+ }
+
+ @Override
+ int onShellCommand(ShellCommand shell) {
+ PrintWriter pw = shell.getOutPrintWriter();
+ String cmd = shell.getNextArgRequired();
+ switch (cmd) {
+ case "start":
+ startTrace(pw);
+ return 0;
+ case "stop":
+ stopTrace(pw);
+ return 0;
+ case "save-for-bugreport":
+ saveForBugreport(pw);
+ return 0;
+ case "status":
+ logAndPrintln(pw, getStatus());
+ return 0;
+ case "frame":
+ setLogFrequency(true /* onFrame */, pw);
+ mBuffer.resetBuffer();
+ return 0;
+ case "transaction":
+ setLogFrequency(false /* onFrame */, pw);
+ mBuffer.resetBuffer();
+ return 0;
+ case "level":
+ String logLevelStr = shell.getNextArgRequired().toLowerCase();
+ switch (logLevelStr) {
+ case "all": {
+ setLogLevel(WindowTraceLogLevel.ALL, pw);
+ break;
+ }
+ case "trim": {
+ setLogLevel(WindowTraceLogLevel.TRIM, pw);
+ break;
+ }
+ case "critical": {
+ setLogLevel(WindowTraceLogLevel.CRITICAL, pw);
+ break;
+ }
+ default: {
+ setLogLevel(WindowTraceLogLevel.TRIM, pw);
+ break;
+ }
+ }
+ mBuffer.resetBuffer();
+ return 0;
+ case "size":
+ setBufferCapacity(Integer.parseInt(shell.getNextArgRequired()) * 1024, pw);
+ mBuffer.resetBuffer();
+ return 0;
+ default:
+ pw.println("Unknown command: " + cmd);
+ pw.println("Window manager trace options:");
+ pw.println(" start: Start logging");
+ pw.println(" stop: Stop logging");
+ pw.println(" save-for-bugreport: Save logging data to file if it's running.");
+ pw.println(" frame: Log trace once per frame");
+ pw.println(" transaction: Log each transaction");
+ pw.println(" size: Set the maximum log size (in KB)");
+ pw.println(" status: Print trace status");
+ pw.println(" level [lvl]: Set the log level between");
+ pw.println(" lvl may be one of:");
+ pw.println(" critical: Only visible windows with reduced information");
+ pw.println(" trim: All windows with reduced");
+ pw.println(" all: All window and information");
+ return -1;
+ }
+ }
+
+ @Override
+ String getStatus() {
+ return "Status: "
+ + ((isEnabled()) ? "Enabled" : "Disabled")
+ + "\n"
+ + "Log level: "
+ + mLogLevel
+ + "\n"
+ + mBuffer.getStatus();
+ }
+
+ @Override
+ protected void startTraceInternal(@Nullable PrintWriter pw) {
+ synchronized (mEnabledLock) {
+ logAndPrintln(pw, "Start tracing to " + mTraceFile + ".");
+ mBuffer.resetBuffer();
+ mEnabled = mEnabledLockFree = true;
+ }
+ log(WHERE_START_TRACING);
+ }
+
+ @Override
+ protected void stopTraceInternal(@Nullable PrintWriter pw) {
+ synchronized (mEnabledLock) {
+ logAndPrintln(pw, "Stop tracing to " + mTraceFile + ". Waiting for traces to flush.");
+ mEnabled = mEnabledLockFree = false;
+
+ if (mEnabled) {
+ logAndPrintln(pw, "ERROR: tracing was re-enabled while waiting for flush.");
+ throw new IllegalStateException("tracing enabled while waiting for flush.");
+ }
+ writeTraceToFileLocked();
+ logAndPrintln(pw, "Trace written to " + mTraceFile + ".");
+ }
+ }
+
+ @Override
+ protected void saveForBugreportInternal(@Nullable PrintWriter pw) {
+ synchronized (mEnabledLock) {
+ if (!mEnabled) {
+ return;
+ }
+ mEnabled = mEnabledLockFree = false;
+ logAndPrintln(pw, "Stop tracing to " + mTraceFile + ". Waiting for traces to flush.");
+ writeTraceToFileLocked();
+ logAndPrintln(pw, "Trace written to " + mTraceFile + ".");
+ logAndPrintln(pw, "Start tracing to " + mTraceFile + ".");
+ mBuffer.resetBuffer();
+ mEnabled = mEnabledLockFree = true;
+ }
+ }
+
+ @Override
+ protected void log(String where) {
+ try {
+ ProtoOutputStream os = new ProtoOutputStream();
+ long token = os.start(ENTRY);
+ dumpToProto(os, mLogLevel, where, SystemClock.elapsedRealtimeNanos());
+ os.end(token);
+ mBuffer.add(os);
+ } catch (Exception e) {
+ Log.wtf(TAG, "Exception while tracing state", e);
+ }
+ }
+
+ @Override
+ protected boolean shouldLogOnFrame() {
+ return mLogOnFrame;
+ }
+
+ @Override
+ protected boolean shouldLogOnTransaction() {
+ return !mLogOnFrame;
+ }
+
+ private void writeTraceToFileLocked() {
+ try {
+ Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "writeTraceToFileLocked");
+ ProtoOutputStream proto = new ProtoOutputStream();
+ proto.write(MAGIC_NUMBER, MAGIC_NUMBER_VALUE);
+ long timeOffsetNs =
+ TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis())
+ - SystemClock.elapsedRealtimeNanos();
+ proto.write(REAL_TO_ELAPSED_TIME_OFFSET_NANOS, timeOffsetNs);
+ mBuffer.writeTraceToFile(mTraceFile, proto);
+ } catch (IOException e) {
+ Log.e(TAG, "Unable to write buffer to file", e);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/wm/utils/DimenPxIntSupplier.java b/services/core/java/com/android/server/wm/utils/DimenPxIntSupplier.java
new file mode 100644
index 000000000000..5e4934500154
--- /dev/null
+++ b/services/core/java/com/android/server/wm/utils/DimenPxIntSupplier.java
@@ -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.server.wm.utils;
+
+import android.annotation.DimenRes;
+import android.annotation.NonNull;
+import android.content.Context;
+
+import java.util.function.IntSupplier;
+
+/**
+ * Cached version of IntSupplier customised to evaluate new dimen in pixels
+ * when density changes.
+ * @hide
+ */
+public class DimenPxIntSupplier implements IntSupplier {
+
+ @NonNull
+ private final Context mContext;
+
+ private final int mResourceId;
+
+ private float mLastDensity = Float.MIN_VALUE;
+ private int mValue = 0;
+
+ public DimenPxIntSupplier(@NonNull Context context, @DimenRes int resourceId) {
+ mContext = context;
+ mResourceId = resourceId;
+ }
+
+ @Override
+ public int getAsInt() {
+ final float newDensity = mContext.getResources().getDisplayMetrics().density;
+ if (newDensity != mLastDensity) {
+ mLastDensity = newDensity;
+ mValue = mContext.getResources().getDimensionPixelSize(mResourceId);
+ }
+ return mValue;
+ }
+}
diff --git a/services/core/jni/com_android_server_companion_virtual_InputController.cpp b/services/core/jni/com_android_server_companion_virtual_InputController.cpp
index a32b0f1526cd..9ec5ae5a8e51 100644
--- a/services/core/jni/com_android_server_companion_virtual_InputController.cpp
+++ b/services/core/jni/com_android_server_companion_virtual_InputController.cpp
@@ -125,6 +125,9 @@ static unique_fd openUinput(const char* readableName, jint vendorId, jint produc
case DeviceType::ROTARY_ENCODER:
ioctl(fd, UI_SET_EVBIT, EV_REL);
ioctl(fd, UI_SET_RELBIT, REL_WHEEL);
+ if (vd_flags::high_resolution_scroll()) {
+ ioctl(fd, UI_SET_RELBIT, REL_WHEEL_HI_RES);
+ }
break;
default:
ALOGE("Invalid input device type %d", static_cast<int32_t>(deviceType));
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 1f0c827083ac..5719810abc5a 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -314,6 +314,7 @@ public:
void getReaderConfiguration(InputReaderConfiguration* outConfig) override;
void notifyInputDevicesChanged(const std::vector<InputDeviceInfo>& inputDevices) override;
+ void notifyConfigurationChanged(nsecs_t when) override;
std::shared_ptr<KeyCharacterMap> getKeyboardLayoutOverlay(
const InputDeviceIdentifier& identifier,
const std::optional<KeyboardLayoutInfo> keyboardLayoutInfo) override;
@@ -331,7 +332,6 @@ public:
void notifySwitch(nsecs_t when, uint32_t switchValues, uint32_t switchMask,
uint32_t policyFlags) override;
- void notifyConfigurationChanged(nsecs_t when) override;
// ANR-related callbacks -- start
void notifyNoFocusedWindowAnr(const std::shared_ptr<InputApplicationHandle>& handle) override;
void notifyWindowUnresponsive(const sp<IBinder>& token, std::optional<gui::Pid> pid,
@@ -382,6 +382,7 @@ public:
PointerControllerInterface::ControllerType type) override;
void notifyPointerDisplayIdChanged(ui::LogicalDisplayId displayId,
const FloatPoint& position) override;
+ void notifyMouseCursorFadedOnTyping() override;
/* --- InputFilterPolicyInterface implementation --- */
void notifyStickyModifierStateChanged(uint32_t modifierState,
@@ -788,6 +789,10 @@ void NativeInputManager::notifyPointerDisplayIdChanged(ui::LogicalDisplayId poin
InputReaderConfiguration::Change::DISPLAY_INFO);
}
+void NativeInputManager::notifyMouseCursorFadedOnTyping() {
+ mInputManager->getReader().notifyMouseCursorFadedOnTyping();
+}
+
void NativeInputManager::notifyStickyModifierStateChanged(uint32_t modifierState,
uint32_t lockedModifierState) {
JNIEnv* env = jniEnv();
@@ -1847,10 +1852,6 @@ static void handleInputChannelDisposed(JNIEnv* env, jobject /* inputChannelObj *
const std::shared_ptr<InputChannel>& inputChannel,
void* data) {
NativeInputManager* im = static_cast<NativeInputManager*>(data);
-
- ALOGW("Input channel object '%s' was disposed without first being removed with "
- "the input manager!",
- inputChannel->getName().c_str());
im->removeInputChannel(inputChannel->getConnectionToken());
}
diff --git a/services/core/xsd/display-device-config/display-device-config.xsd b/services/core/xsd/display-device-config/display-device-config.xsd
index eeb8b9b0b469..ec7406ae6219 100644
--- a/services/core/xsd/display-device-config/display-device-config.xsd
+++ b/services/core/xsd/display-device-config/display-device-config.xsd
@@ -315,6 +315,42 @@
<xs:element name="screenBrightnessRampDecrease" type="nonNegativeDecimal">
<xs:annotation name="final"/>
</xs:element>
+
+ <!-- The minimum HDR layer % at which hdr boost will be applied with transition point cap.
+ Should be lower or equal to minimumHdrPercentOfScreenForHbm. -->
+ <xs:element name="minimumHdrPercentOfScreenForNbm" type="nonNegativeDecimal"
+ minOccurs="0" maxOccurs="1">
+ <xs:annotation name="nullable"/>
+ <xs:annotation name="final"/>
+ </xs:element>
+ <!-- The minimum HDR layer size at which hdr boost will be applied. -->
+ <xs:element name="minimumHdrPercentOfScreenForHbm" type="nonNegativeDecimal"
+ minOccurs="0" maxOccurs="1">
+ <xs:annotation name="nullable"/>
+ <xs:annotation name="final"/>
+ </xs:element>
+ <!-- If hdr boost is allowed in low power mode. -->
+ <xs:element name="allowInLowPowerMode" type="xs:boolean" minOccurs="0" maxOccurs="1">
+ <xs:annotation name="nonnull"/>
+ <xs:annotation name="final"/>
+ </xs:element>
+ <!-- sdrNits, hdrRatio This LUT specifies how to boost HDR brightness at given SDR brightness (nits). -->
+ <!-- sdr brightness to hdr boost ratio map
+ Format: first = sdrNits, second = hdrRatio. E.g. :
+ <sdrHdrRatioMap>
+ <point>
+ <first>2.0</first> // sdrNits
+ <second>4.0</second> // hdrRatio
+ </point>
+ ....
+ </sdrHdrRatioMap>
+ -->
+ <xs:element type="nonNegativeFloatToFloatMap" name="sdrHdrRatioMap" minOccurs="0" maxOccurs="1">
+ <xs:annotation name="nullable"/>
+ <xs:annotation name="final"/>
+ </xs:element>
+
+
</xs:complexType>
<!-- Maps to PowerManager.THERMAL_STATUS_* values. -->
diff --git a/services/core/xsd/display-device-config/schema/current.txt b/services/core/xsd/display-device-config/schema/current.txt
index 757b23a2df7e..68d74cf723e1 100644
--- a/services/core/xsd/display-device-config/schema/current.txt
+++ b/services/core/xsd/display-device-config/schema/current.txt
@@ -226,16 +226,24 @@ package com.android.server.display.config {
public class HdrBrightnessConfig {
ctor public HdrBrightnessConfig();
+ method @NonNull public final boolean getAllowInLowPowerMode();
method public final java.math.BigInteger getBrightnessDecreaseDebounceMillis();
method public final java.math.BigInteger getBrightnessIncreaseDebounceMillis();
method @NonNull public final com.android.server.display.config.NonNegativeFloatToFloatMap getBrightnessMap();
+ method @Nullable public final java.math.BigDecimal getMinimumHdrPercentOfScreenForHbm();
+ method @Nullable public final java.math.BigDecimal getMinimumHdrPercentOfScreenForNbm();
method public final java.math.BigDecimal getScreenBrightnessRampDecrease();
method public final java.math.BigDecimal getScreenBrightnessRampIncrease();
+ method @Nullable public final com.android.server.display.config.NonNegativeFloatToFloatMap getSdrHdrRatioMap();
+ method public final void setAllowInLowPowerMode(@NonNull boolean);
method public final void setBrightnessDecreaseDebounceMillis(java.math.BigInteger);
method public final void setBrightnessIncreaseDebounceMillis(java.math.BigInteger);
method public final void setBrightnessMap(@NonNull com.android.server.display.config.NonNegativeFloatToFloatMap);
+ method public final void setMinimumHdrPercentOfScreenForHbm(@Nullable java.math.BigDecimal);
+ method public final void setMinimumHdrPercentOfScreenForNbm(@Nullable java.math.BigDecimal);
method public final void setScreenBrightnessRampDecrease(java.math.BigDecimal);
method public final void setScreenBrightnessRampIncrease(java.math.BigDecimal);
+ method public final void setSdrHdrRatioMap(@Nullable com.android.server.display.config.NonNegativeFloatToFloatMap);
}
public class HighBrightnessMode {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index e5a1ebfdc404..db4b171152a7 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -381,6 +381,9 @@ public final class SystemServer implements Dumpable {
+ "OnDevicePersonalizationSystemService$Lifecycle";
private static final String UPDATABLE_DEVICE_CONFIG_SERVICE_CLASS =
"com.android.server.deviceconfig.DeviceConfigInit$Lifecycle";
+ private static final String CRASHRECOVERY_MODULE_LIFECYCLE_CLASS =
+ "com.android.server.crashrecovery.CrashRecoveryModule$Lifecycle";
+
/*
* Implementation class names and jar locations for services in
@@ -1196,15 +1199,18 @@ public final class SystemServer implements Dumpable {
mSystemServiceManager.startService(RecoverySystemService.Lifecycle.class);
t.traceEnd();
- // Initialize RescueParty.
- RescueParty.registerHealthObserver(mSystemContext);
- 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.
- PackageWatchdog.getInstance(mSystemContext).noteBoot();
+ if (!Flags.refactorCrashrecovery()) {
+ // Initialize RescueParty.
+ RescueParty.registerHealthObserver(mSystemContext);
+ 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.
+ PackageWatchdog.getInstance(mSystemContext).noteBoot();
+ }
}
+
// Manages LEDs and display backlight so we need it to bring up the display.
t.traceBegin("StartLightsService");
mSystemServiceManager.startService(LightsService.class);
@@ -2931,12 +2937,18 @@ public final class SystemServer implements Dumpable {
mPackageManagerService.systemReady();
t.traceEnd();
- if (Flags.recoverabilityDetection()) {
- // Now that we have the essential services needed for mitigations, register the boot
- // with package watchdog.
- // Note that we just booted, which might send out a rescue party if we're stuck in a
- // runtime restart loop.
- PackageWatchdog.getInstance(mSystemContext).noteBoot();
+ if (Flags.refactorCrashrecovery()) {
+ t.traceBegin("StartCrashRecoveryModule");
+ mSystemServiceManager.startService(CRASHRECOVERY_MODULE_LIFECYCLE_CLASS);
+ t.traceEnd();
+ } else {
+ if (Flags.recoverabilityDetection()) {
+ // Now that we have the essential services needed for mitigations, register the boot
+ // with package watchdog.
+ // Note that we just booted, which might send out a rescue party if we're stuck in a
+ // runtime restart loop.
+ PackageWatchdog.getInstance(mSystemContext).noteBoot();
+ }
}
t.traceBegin("MakeDisplayManagerServiceReady");
diff --git a/services/permission/java/com/android/server/permission/access/util/AtomicFileExtensions.kt b/services/permission/java/com/android/server/permission/access/util/AtomicFileExtensions.kt
index 6b20ef1d5519..996daf5a5f68 100644
--- a/services/permission/java/com/android/server/permission/access/util/AtomicFileExtensions.kt
+++ b/services/permission/java/com/android/server/permission/access/util/AtomicFileExtensions.kt
@@ -47,9 +47,8 @@ inline fun AtomicFile.readWithReserveCopy(block: (FileInputStream) -> Unit) {
/** Write to actual file and reserve file. */
@Throws(IOException::class)
inline fun AtomicFile.writeWithReserveCopy(block: (FileOutputStream) -> Unit) {
- val reserveFile = File(baseFile.parentFile, baseFile.name + ".reservecopy")
- reserveFile.delete()
writeInlined(block)
+ val reserveFile = File(baseFile.parentFile, baseFile.name + ".reservecopy")
try {
FileInputStream(baseFile).use { inputStream ->
FileOutputStream(reserveFile).use { outputStream ->
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java
index 2029b71034eb..8f630af476c7 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java
@@ -99,6 +99,12 @@ public class InputMethodServiceTest {
InputMethodServiceWrapper.getInputMethodServiceWrapperForTesting();
assertThat(mInputMethodService).isNotNull();
+ // The activity gets focus.
+ assertThat(mActivity.hasWindowFocus()).isTrue();
+ assertThat(mInputMethodService.getCurrentInputEditorInfo()).isNotNull();
+ assertThat(mInputMethodService.getCurrentInputEditorInfo().packageName)
+ .isEqualTo(mTargetPackageName);
+
// The editor won't bring up keyboard by default.
assertThat(mInputMethodService.getCurrentInputStarted()).isTrue();
assertThat(mInputMethodService.getCurrentInputViewStarted()).isFalse();
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java
index f83144f176d3..bacde101bf36 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java
@@ -25,6 +25,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.notNull;
@@ -38,6 +39,7 @@ import android.app.ActivityManagerInternal;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.IntentFilter;
+import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.res.Configuration;
import android.hardware.input.IInputManager;
@@ -49,6 +51,7 @@ import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
+import android.util.ArraySet;
import android.view.InputChannel;
import android.view.inputmethod.EditorInfo;
import android.window.ImeOnBackInvokedDispatcher;
@@ -134,6 +137,14 @@ public class InputMethodManagerServiceTestBase {
protected boolean mIsLargeScreen;
private InputManagerGlobal.TestSession mInputManagerGlobalSession;
+ private final ArraySet<Class<?>> mRegisteredLocalServices = new ArraySet<>();
+
+ protected <T> void addLocalServiceMock(Class<T> type, T service) {
+ mRegisteredLocalServices.add(type);
+ LocalServices.removeServiceForTest(type);
+ LocalServices.addService(type, service);
+ }
+
@BeforeClass
public static void setupClass() {
// Make sure DeviceConfig's lazy-initialized ContentProvider gets
@@ -148,7 +159,7 @@ public class InputMethodManagerServiceTestBase {
mockitoSession()
.initMocks(this)
.strictness(Strictness.LENIENT)
- .spyStatic(LocalServices.class)
+ .spyStatic(InputMethodUtils.class)
.mockStatic(ServiceManager.class)
.mockStatic(SystemServerInitThreadPool.class)
.startMocking();
@@ -163,18 +174,13 @@ public class InputMethodManagerServiceTestBase {
mEditorInfo.packageName = TEST_EDITOR_PKG_NAME;
// Injecting and mocking local services.
- doReturn(mMockWindowManagerInternal)
- .when(() -> LocalServices.getService(WindowManagerInternal.class));
- doReturn(mMockActivityManagerInternal)
- .when(() -> LocalServices.getService(ActivityManagerInternal.class));
- doReturn(mMockPackageManagerInternal)
- .when(() -> LocalServices.getService(PackageManagerInternal.class));
- doReturn(mMockInputManagerInternal)
- .when(() -> LocalServices.getService(InputManagerInternal.class));
- doReturn(mMockUserManagerInternal)
- .when(() -> LocalServices.getService(UserManagerInternal.class));
- doReturn(mMockImeTargetVisibilityPolicy)
- .when(() -> LocalServices.getService(ImeTargetVisibilityPolicy.class));
+ addLocalServiceMock(WindowManagerInternal.class, mMockWindowManagerInternal);
+ addLocalServiceMock(ActivityManagerInternal.class, mMockActivityManagerInternal);
+ addLocalServiceMock(PackageManagerInternal.class, mMockPackageManagerInternal);
+ addLocalServiceMock(InputManagerInternal.class, mMockInputManagerInternal);
+ addLocalServiceMock(UserManagerInternal.class, mMockUserManagerInternal);
+ addLocalServiceMock(ImeTargetVisibilityPolicy.class, mMockImeTargetVisibilityPolicy);
+
doReturn(mMockIInputMethodManager)
.when(() -> ServiceManager.getServiceOrThrow(Context.INPUT_METHOD_SERVICE));
doReturn(mMockIPlatformCompat)
@@ -224,6 +230,10 @@ public class InputMethodManagerServiceTestBase {
.thenReturn(TEST_IME_TARGET_INFO);
when(mMockInputMethodClient.asBinder()).thenReturn(mMockInputMethodBinder);
+ // This changes the real IME component state. Not appropriate to do in tests.
+ doNothing().when(() -> InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed(
+ any(PackageManager.class), anyList()));
+
// Used by lazy initializing draw IMS nav bar at InputMethodManagerService#systemRunning(),
// which is ok to be mocked out for now.
doReturn(null).when(() -> SystemServerInitThreadPool.submit(any(), anyString()));
@@ -233,14 +243,20 @@ public class InputMethodManagerServiceTestBase {
"immstest1",
Process.THREAD_PRIORITY_FOREGROUND,
true /* allowIo */);
+ mServiceThread.start();
mIoThread =
new ServiceThread(
"immstest2",
Process.THREAD_PRIORITY_FOREGROUND,
true /* allowIo */);
+ mIoThread.start();
+
+ final var ioHandler = spy(Handler.createAsync(mIoThread.getLooper()));
+ doReturn(true).when(ioHandler).post(any());
+
mInputMethodManagerService = new InputMethodManagerService(mContext,
InputMethodManagerService.shouldEnableConcurrentMultiUserMode(mContext),
- mServiceThread, mIoThread,
+ mServiceThread.getLooper(), ioHandler,
unusedUserId -> mMockInputMethodBindingController);
spyOn(mInputMethodManagerService);
@@ -252,16 +268,9 @@ public class InputMethodManagerServiceTestBase {
// Public local InputMethodManagerService.
LocalServices.removeServiceForTest(InputMethodManagerInternal.class);
lifecycle.onStart();
- try {
- // After this boot phase, services can broadcast Intents.
- lifecycle.onBootPhase(SystemService.PHASE_ACTIVITY_MANAGER_READY);
- } catch (SecurityException e) {
- // Security exception to permission denial is expected in test, mocking out to ensure
- // InputMethodManagerService as system ready state.
- if (!e.getMessage().contains("Permission Denial: not allowed to send broadcast")) {
- throw e;
- }
- }
+
+ // After this boot phase, services can broadcast Intents.
+ lifecycle.onBootPhase(SystemService.PHASE_ACTIVITY_MANAGER_READY);
// Call InputMethodManagerService#addClient() as a preparation to start interacting with it.
mInputMethodManagerService.addClient(mMockInputMethodClient, mMockRemoteInputConnection, 0);
@@ -289,7 +298,7 @@ public class InputMethodManagerServiceTestBase {
if (mInputManagerGlobalSession != null) {
mInputManagerGlobalSession.close();
}
- LocalServices.removeServiceForTest(InputMethodManagerInternal.class);
+ mRegisteredLocalServices.forEach(LocalServices::removeServiceForTest);
}
protected void verifyShowSoftInput(boolean setVisible, boolean showSoftInput)
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceWindowGainedFocusTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceWindowGainedFocusTest.java
index 9f46d0ba7df6..ffc4df8f2069 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceWindowGainedFocusTest.java
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceWindowGainedFocusTest.java
@@ -50,7 +50,6 @@ import com.android.internal.inputmethod.InputBindResult;
import com.android.internal.inputmethod.InputMethodDebug;
import com.android.internal.inputmethod.StartInputFlags;
import com.android.internal.inputmethod.StartInputReason;
-import com.android.server.LocalServices;
import com.android.server.companion.virtual.VirtualDeviceManagerInternal;
import com.android.server.wm.WindowManagerInternal;
@@ -270,8 +269,7 @@ public class InputMethodManagerServiceWindowGainedFocusTest
@Test
public void startInputOrWindowGainedFocus_localeHintsOverride() throws RemoteException {
- doReturn(mMockVdmInternal).when(
- () -> LocalServices.getService(VirtualDeviceManagerInternal.class));
+ addLocalServiceMock(VirtualDeviceManagerInternal.class, mMockVdmInternal);
LocaleList overrideLocale = LocaleList.forLanguageTags("zh-CN");
doReturn(overrideLocale).when(mMockVdmInternal).getPreferredLocaleListForUid(anyInt());
mockHasImeFocusAndRestoreImeVisibility(false /* restoreImeVisibility */);
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/UserDataRepositoryTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/UserDataRepositoryTest.java
index e2f3eec1a20b..81fb1a092887 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/UserDataRepositoryTest.java
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/UserDataRepositoryTest.java
@@ -18,23 +18,12 @@ package com.android.server.inputmethod;
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-import android.content.pm.UserInfo;
-import android.os.ConditionVariable;
-import android.os.Handler;
-import android.os.Looper;
import android.platform.test.ravenwood.RavenwoodRule;
-import com.android.server.pm.UserManagerInternal;
-
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
-import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -52,13 +41,8 @@ public final class UserDataRepositoryTest {
.setProvideMainThread(true).build();
@Mock
- private UserManagerInternal mMockUserManagerInternal;
-
- @Mock
private InputMethodManagerService mMockInputMethodManagerService;
- private Handler mHandler;
-
private IntFunction<InputMethodBindingController> mBindingControllerFactory;
@Before
@@ -66,7 +50,6 @@ public final class UserDataRepositoryTest {
MockitoAnnotations.initMocks(this);
SecureSettingsWrapper.startTestMode();
- mHandler = new Handler(Looper.getMainLooper());
mBindingControllerFactory = new IntFunction<InputMethodBindingController>() {
@Override
@@ -81,54 +64,20 @@ public final class UserDataRepositoryTest {
SecureSettingsWrapper.endTestMode();
}
- @Test
- public void testUserDataRepository_addsNewUserInfoOnUserCreatedEvent() {
- // Create UserDataRepository and capture the user lifecycle listener
- final var captor = ArgumentCaptor.forClass(UserManagerInternal.UserLifecycleListener.class);
- final var bindingControllerFactorySpy = spy(mBindingControllerFactory);
- final var repository = new UserDataRepository(mHandler,
- mMockUserManagerInternal, bindingControllerFactorySpy);
-
- verify(mMockUserManagerInternal, times(1)).addUserLifecycleListener(captor.capture());
- final var listener = captor.getValue();
-
- // Assert that UserDataRepository is empty and then call onUserCreated
- assertThat(collectUserData(repository)).isEmpty();
- final var userInfo = new UserInfo();
- userInfo.id = ANY_USER_ID;
- listener.onUserCreated(userInfo, /* unused token */ new Object());
- waitForIdle();
-
- // Assert UserDataRepository contains the expected UserData
- final var allUserData = collectUserData(repository);
- assertThat(allUserData).hasSize(1);
- assertThat(allUserData.get(0).mUserId).isEqualTo(ANY_USER_ID);
-
- // Assert UserDataRepository called the InputMethodBindingController creator function.
- verify(bindingControllerFactorySpy).apply(ANY_USER_ID);
- assertThat(allUserData.get(0).mBindingController.getUserId()).isEqualTo(ANY_USER_ID);
- }
-
+ // TODO(b/352615651): Move this to end-to-end test.
@Test
public void testUserDataRepository_removesUserInfoOnUserRemovedEvent() {
- // Create UserDataRepository and capture the user lifecycle listener
- final var captor = ArgumentCaptor.forClass(UserManagerInternal.UserLifecycleListener.class);
- final var repository = new UserDataRepository(mHandler,
- mMockUserManagerInternal,
+ // Create UserDataRepository
+ final var repository = new UserDataRepository(
userId -> new InputMethodBindingController(userId, mMockInputMethodManagerService));
- verify(mMockUserManagerInternal, times(1)).addUserLifecycleListener(captor.capture());
- final var listener = captor.getValue();
-
// Add one UserData ...
- final var userInfo = new UserInfo();
- userInfo.id = ANY_USER_ID;
- listener.onUserCreated(userInfo, /* unused token */ new Object());
- waitForIdle();
+ final var userData = repository.getOrCreate(ANY_USER_ID);
+ assertThat(userData.mUserId).isEqualTo(ANY_USER_ID);
+
// ... and then call onUserRemoved
assertThat(collectUserData(repository)).hasSize(1);
- listener.onUserRemoved(userInfo);
- waitForIdle();
+ repository.remove(ANY_USER_ID);
// Assert UserDataRepository is now empty
assertThat(collectUserData(repository)).isEmpty();
@@ -136,13 +85,10 @@ public final class UserDataRepositoryTest {
@Test
public void testGetOrCreate() {
- final var repository = new UserDataRepository(mHandler,
- mMockUserManagerInternal, mBindingControllerFactory);
+ final var repository = new UserDataRepository(mBindingControllerFactory);
- synchronized (ImfLock.class) {
- final var userData = repository.getOrCreate(ANY_USER_ID);
- assertThat(userData.mUserId).isEqualTo(ANY_USER_ID);
- }
+ final var userData = repository.getOrCreate(ANY_USER_ID);
+ assertThat(userData.mUserId).isEqualTo(ANY_USER_ID);
final var allUserData = collectUserData(repository);
assertThat(allUserData).hasSize(1);
@@ -154,15 +100,8 @@ public final class UserDataRepositoryTest {
private List<UserDataRepository.UserData> collectUserData(UserDataRepository repository) {
final var collected = new ArrayList<UserDataRepository.UserData>();
- synchronized (ImfLock.class) {
- repository.forAllUserData(userData -> collected.add(userData));
- }
+ repository.forAllUserData(userData -> collected.add(userData));
return collected;
}
- private void waitForIdle() {
- final var done = new ConditionVariable();
- mHandler.post(done::open);
- done.block();
- }
}
diff --git a/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/src/com/android/apps/inputmethod/simpleime/ims/InputMethodServiceWrapper.java b/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/src/com/android/apps/inputmethod/simpleime/ims/InputMethodServiceWrapper.java
index b706a654e3a8..67212b60f1b8 100644
--- a/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/src/com/android/apps/inputmethod/simpleime/ims/InputMethodServiceWrapper.java
+++ b/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/src/com/android/apps/inputmethod/simpleime/ims/InputMethodServiceWrapper.java
@@ -53,13 +53,14 @@ public class InputMethodServiceWrapper extends InputMethodService {
@Override
public void onStartInput(EditorInfo info, boolean restarting) {
- Log.i(TAG, "onStartInput() editor=" + info + ", restarting=" + restarting);
+ Log.i(TAG, "onStartInput() editor=" + dumpEditorInfo(info) + ", restarting=" + restarting);
super.onStartInput(info, restarting);
}
@Override
public void onStartInputView(EditorInfo info, boolean restarting) {
- Log.i(TAG, "onStartInputView() editor=" + info + ", restarting=" + restarting);
+ Log.i(TAG, "onStartInputView() editor=" + dumpEditorInfo(info)
+ + ", restarting=" + restarting);
super.onStartInputView(info, restarting);
mInputViewStarted = true;
if (mCountDownLatchForTesting != null) {
@@ -99,4 +100,14 @@ public class InputMethodServiceWrapper extends InputMethodService {
mCountDownLatchForTesting.countDown();
}
}
+
+ private String dumpEditorInfo(EditorInfo info) {
+ var sb = new StringBuilder();
+ sb.append("EditorInfo{packageName=").append(info.packageName);
+ sb.append(" fieldId=").append(info.fieldId);
+ sb.append(" hintText=").append(info.hintText);
+ sb.append(" privateImeOptions=").append(info.privateImeOptions);
+ sb.append("}");
+ return sb.toString();
+ }
}
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java
index 89b4aea216f9..71383069d08a 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -1027,6 +1027,25 @@ public class PackageManagerSettingsTests {
}
@Test
+ public void testWriteReadDebuggable() {
+ Settings settings = makeSettings();
+ PackageSetting packageSetting = createPackageSetting(PACKAGE_NAME_1);
+ packageSetting.setAppId(Process.FIRST_APPLICATION_UID);
+ packageSetting.setPkg(PackageImpl.forTesting(PACKAGE_NAME_1).hideAsParsed()
+ .setUid(packageSetting.getAppId())
+ .hideAsFinal());
+
+ packageSetting.setDebuggable(true);
+ settings.mPackages.put(PACKAGE_NAME_1, packageSetting);
+
+ settings.writeLPr(computer, /* sync= */ true);
+ settings.mPackages.clear();
+
+ assertThat(settings.readLPw(computer, createFakeUsers()), is(true));
+ assertThat(settings.getPackageLPr(PACKAGE_NAME_1).isDebuggable(), is(true));
+ }
+
+ @Test
public void testWriteReadArchiveState() {
Settings settings = makeSettings();
PackageSetting packageSetting = createPackageSetting(PACKAGE_NAME_1);
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayBrightnessStateTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayBrightnessStateTest.java
index bba4c8d64c86..f690b1bbfccf 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayBrightnessStateTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayBrightnessStateTest.java
@@ -44,7 +44,7 @@ public class DisplayBrightnessStateTest {
@Test
public void validateAllDisplayBrightnessStateFieldsAreSetAsExpected() {
float brightness = 0.3f;
- float sdrBrightness = 0.2f;
+ float hdrBrightness = 0.4f;
boolean shouldUseAutoBrightness = true;
boolean shouldUpdateScreenBrightnessSetting = true;
int brightnessAdjustmentFlag = 2;
@@ -53,7 +53,7 @@ public class DisplayBrightnessStateTest {
brightnessReason.setModifier(BrightnessReason.MODIFIER_DIMMED);
DisplayBrightnessState displayBrightnessState = mDisplayBrightnessStateBuilder
.setBrightness(brightness)
- .setSdrBrightness(sdrBrightness)
+ .setHdrBrightness(hdrBrightness)
.setBrightnessReason(brightnessReason)
.setShouldUseAutoBrightness(shouldUseAutoBrightness)
.setShouldUpdateScreenBrightnessSetting(shouldUpdateScreenBrightnessSetting)
@@ -62,7 +62,7 @@ public class DisplayBrightnessStateTest {
.build();
assertEquals(displayBrightnessState.getBrightness(), brightness, FLOAT_DELTA);
- assertEquals(displayBrightnessState.getSdrBrightness(), sdrBrightness, FLOAT_DELTA);
+ assertEquals(displayBrightnessState.getHdrBrightness(), hdrBrightness, FLOAT_DELTA);
assertEquals(displayBrightnessState.getBrightnessReason(), brightnessReason);
assertEquals(displayBrightnessState.getShouldUseAutoBrightness(), shouldUseAutoBrightness);
assertEquals(shouldUpdateScreenBrightnessSetting,
@@ -78,7 +78,7 @@ public class DisplayBrightnessStateTest {
DisplayBrightnessState state1 = new DisplayBrightnessState.Builder()
.setBrightnessReason(reason)
.setBrightness(0.26f)
- .setSdrBrightness(0.23f)
+ .setHdrBrightness(0.29f)
.setShouldUseAutoBrightness(false)
.setShouldUpdateScreenBrightnessSetting(true)
.build();
@@ -91,8 +91,8 @@ public class DisplayBrightnessStateTest {
sb.append("DisplayBrightnessState:")
.append("\n brightness:")
.append(displayBrightnessState.getBrightness())
- .append("\n sdrBrightness:")
- .append(displayBrightnessState.getSdrBrightness())
+ .append("\n hdrBrightness:")
+ .append(displayBrightnessState.getHdrBrightness())
.append("\n brightnessReason:")
.append(displayBrightnessState.getBrightnessReason())
.append("\n shouldUseAutoBrightness:")
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java
index 9a25b1acfaae..343792336247 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java
@@ -54,6 +54,7 @@ import androidx.test.filters.SmallTest;
import com.android.internal.R;
import com.android.server.display.config.HdrBrightnessData;
+import com.android.server.display.config.HighBrightnessModeData;
import com.android.server.display.config.HysteresisLevels;
import com.android.server.display.config.IdleScreenRefreshRateTimeoutLuxThresholdPoint;
import com.android.server.display.config.RefreshRateData;
@@ -436,7 +437,7 @@ public final class DisplayDeviceConfigTest {
public void testHighBrightnessModeDataFromDisplayConfig() throws IOException {
setupDisplayDeviceConfigFromDisplayConfigFile();
- DisplayDeviceConfig.HighBrightnessModeData hbmData =
+ HighBrightnessModeData hbmData =
mDisplayDeviceConfig.getHighBrightnessModeData();
assertNotNull(hbmData);
assertEquals(BRIGHTNESS[1], hbmData.transitionPoint, ZERO_DELTA);
@@ -671,14 +672,14 @@ public final class DisplayDeviceConfigTest {
HdrBrightnessData data = mDisplayDeviceConfig.getHdrBrightnessData();
assertNotNull(data);
- assertEquals(2, data.mMaxBrightnessLimits.size());
- assertEquals(13000, data.mBrightnessDecreaseDebounceMillis);
- assertEquals(0.1f, data.mScreenBrightnessRampDecrease, SMALL_DELTA);
- assertEquals(1000, data.mBrightnessIncreaseDebounceMillis);
- assertEquals(0.11f, data.mScreenBrightnessRampIncrease, SMALL_DELTA);
-
- assertEquals(0.3f, data.mMaxBrightnessLimits.get(500f), SMALL_DELTA);
- assertEquals(0.6f, data.mMaxBrightnessLimits.get(1200f), SMALL_DELTA);
+ assertEquals(2, data.maxBrightnessLimits.size());
+ assertEquals(13000, data.brightnessDecreaseDebounceMillis);
+ assertEquals(0.1f, data.screenBrightnessRampDecrease, SMALL_DELTA);
+ assertEquals(1000, data.brightnessIncreaseDebounceMillis);
+ assertEquals(0.11f, data.screenBrightnessRampIncrease, SMALL_DELTA);
+
+ assertEquals(0.3f, data.maxBrightnessLimits.get(500f), SMALL_DELTA);
+ assertEquals(0.6f, data.maxBrightnessLimits.get(1200f), SMALL_DELTA);
}
private void verifyConfigValuesFromConfigResource() {
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
index 2018e1a3ae62..5c291569b8d8 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
@@ -83,6 +83,7 @@ import com.android.server.display.brightness.BrightnessReason;
import com.android.server.display.brightness.clamper.BrightnessClamperController;
import com.android.server.display.brightness.clamper.HdrClamper;
import com.android.server.display.color.ColorDisplayService;
+import com.android.server.display.config.HighBrightnessModeData;
import com.android.server.display.config.HysteresisLevels;
import com.android.server.display.config.SensorData;
import com.android.server.display.feature.DisplayManagerFlags;
@@ -2425,7 +2426,7 @@ public final class DisplayPowerControllerTest {
@Override
HighBrightnessModeController getHighBrightnessModeController(Handler handler, int width,
int height, IBinder displayToken, String displayUniqueId, float brightnessMin,
- float brightnessMax, DisplayDeviceConfig.HighBrightnessModeData hbmData,
+ float brightnessMax, HighBrightnessModeData hbmData,
HighBrightnessModeController.HdrBrightnessDeviceConfig hdrBrightnessCfg,
Runnable hbmChangeCallback, HighBrightnessModeMetadata hbmMetadata,
Context context) {
diff --git a/services/tests/displayservicetests/src/com/android/server/display/HighBrightnessModeControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/HighBrightnessModeControllerTest.java
index 8e01a11cb23f..cde87b9b89b2 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/HighBrightnessModeControllerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/HighBrightnessModeControllerTest.java
@@ -23,7 +23,6 @@ import static android.hardware.display.BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLI
import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED;
import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED;
import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_OFF_DUE_TO_DISPLAY_STATE;
-import static com.android.server.display.DisplayDeviceConfig.HDR_PERCENT_OF_SCREEN_REQUIRED_DEFAULT;
import static com.android.server.display.HighBrightnessModeController.HBM_TRANSITION_POINT_INVALID;
import static org.junit.Assert.assertEquals;
@@ -56,8 +55,8 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.test.FakeSettingsProvider;
import com.android.internal.util.test.FakeSettingsProviderRule;
-import com.android.server.display.DisplayDeviceConfig.HighBrightnessModeData;
import com.android.server.display.HighBrightnessModeController.Injector;
+import com.android.server.display.config.HighBrightnessModeData;
import com.android.server.testutils.OffsettableClock;
import org.junit.Before;
@@ -77,6 +76,7 @@ public class HighBrightnessModeControllerTest {
private static final long TIME_ALLOWED_IN_WINDOW_MILLIS = 12 * 1000;
private static final long TIME_MINIMUM_AVAILABLE_TO_ENABLE_MILLIS = 5 * 1000;
private static final boolean ALLOW_IN_LOW_POWER_MODE = false;
+ private static final float HDR_PERCENT_OF_SCREEN_REQUIRED_DEFAULT = 0.5f;
private static final float DEFAULT_MIN = 0.01f;
private static final float DEFAULT_MAX = 0.80f;
@@ -103,7 +103,8 @@ public class HighBrightnessModeControllerTest {
private static final HighBrightnessModeData DEFAULT_HBM_DATA =
new HighBrightnessModeData(MINIMUM_LUX, TRANSITION_POINT, TIME_WINDOW_MILLIS,
TIME_ALLOWED_IN_WINDOW_MILLIS, TIME_MINIMUM_AVAILABLE_TO_ENABLE_MILLIS,
- ALLOW_IN_LOW_POWER_MODE, HDR_PERCENT_OF_SCREEN_REQUIRED_DEFAULT);
+ ALLOW_IN_LOW_POWER_MODE, HDR_PERCENT_OF_SCREEN_REQUIRED_DEFAULT,
+ null, null, true);
@Before
public void setUp() {
diff --git a/services/tests/displayservicetests/src/com/android/server/display/HighBrightnessModeMetadataMapperTest.java b/services/tests/displayservicetests/src/com/android/server/display/HighBrightnessModeMetadataMapperTest.java
index 7e7ccf733876..7132bc1687ca 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/HighBrightnessModeMetadataMapperTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/HighBrightnessModeMetadataMapperTest.java
@@ -22,6 +22,8 @@ import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.when;
+import com.android.server.display.config.HighBrightnessModeData;
+
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
@@ -39,7 +41,7 @@ public class HighBrightnessModeMetadataMapperTest {
private DisplayDeviceConfig mDdcMock;
@Mock
- private DisplayDeviceConfig.HighBrightnessModeData mHbmDataMock;
+ private HighBrightnessModeData mHbmDataMock;
private HighBrightnessModeMetadataMapper mHighBrightnessModeMetadataMapper;
diff --git a/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java b/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java
index 6d138c5b6b29..1729ad5ff19f 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java
@@ -16,7 +16,7 @@
package com.android.server.display;
-import static android.hardware.devicestate.DeviceStateManager.INVALID_DEVICE_STATE_IDENTIFIER;
+import static android.hardware.devicestate.DeviceStateManager.INVALID_DEVICE_STATE;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.DEFAULT_DISPLAY_GROUP;
import static android.view.Display.FLAG_REAR;
@@ -62,9 +62,11 @@ 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.PropertyInvalidatedCache;
import android.content.Context;
import android.content.res.Resources;
+import android.hardware.devicestate.DeviceState;
import android.os.Handler;
import android.os.IPowerManager;
import android.os.IThermalService;
@@ -103,7 +105,9 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
+import java.util.Set;
@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -111,9 +115,12 @@ public class LogicalDisplayMapperTest {
private static int sUniqueTestDisplayId = 0;
private static final int TIMEOUT_STATE_TRANSITION_MILLIS = 500;
private static final int FOLD_SETTLE_DELAY = 1000;
- private static final int DEVICE_STATE_CLOSED = 0;
- private static final int DEVICE_STATE_HALF_OPEN = 1;
- private static final int DEVICE_STATE_OPEN = 2;
+ private static final DeviceState DEVICE_STATE_CLOSED = createDeviceState(0, "Zero",
+ Set.of(DeviceState.PROPERTY_POWER_CONFIGURATION_TRIGGER_SLEEP), Collections.emptySet());
+ private static final DeviceState DEVICE_STATE_HALF_OPEN = createDeviceState(1, "One",
+ Set.of(DeviceState.PROPERTY_POWER_CONFIGURATION_TRIGGER_WAKE), Collections.emptySet());
+ private static final DeviceState DEVICE_STATE_OPEN = createDeviceState(2, "Two",
+ Set.of(DeviceState.PROPERTY_POWER_CONFIGURATION_TRIGGER_WAKE), Collections.emptySet());
private static final int FLAG_GO_TO_SLEEP_ON_FOLD = 0;
private static final int FLAG_GO_TO_SLEEP_FLAG_SOFT_SLEEP = 2;
private static int sNextNonDefaultDisplayId = DEFAULT_DISPLAY + 1;
@@ -703,8 +710,7 @@ public class LogicalDisplayMapperTest {
/* isInteractive= */true,
/* isBootCompleted= */true));
assertFalse(mLogicalDisplayMapper.shouldDeviceBePutToSleep(DEVICE_STATE_CLOSED,
- INVALID_DEVICE_STATE_IDENTIFIER,
- /* isInteractive= */true,
+ INVALID_DEVICE_STATE /* currentState */, /* isInteractive= */true,
/* isBootCompleted= */true));
}
@@ -932,7 +938,7 @@ public class LogicalDisplayMapperTest {
// We can only have one default display
assertEquals(DEFAULT_DISPLAY, id(display1));
- mLogicalDisplayMapper.setDeviceStateLocked(0);
+ mLogicalDisplayMapper.setDeviceStateLocked(DEVICE_STATE_CLOSED);
advanceTime(1000);
// The new state is not applied until the boot is completed
assertTrue(mLogicalDisplayMapper.getDisplayLocked(device1).isEnabledLocked());
@@ -953,7 +959,7 @@ public class LogicalDisplayMapperTest {
assertEquals("concurrent", mLogicalDisplayMapper.getDisplayLocked(device2)
.getDisplayInfoLocked().thermalBrightnessThrottlingDataId);
- mLogicalDisplayMapper.setDeviceStateLocked(1);
+ mLogicalDisplayMapper.setDeviceStateLocked(DEVICE_STATE_HALF_OPEN);
advanceTime(1000);
assertFalse(mLogicalDisplayMapper.getDisplayLocked(device1).isEnabledLocked());
assertTrue(mLogicalDisplayMapper.getDisplayLocked(device2).isEnabledLocked());
@@ -966,7 +972,7 @@ public class LogicalDisplayMapperTest {
mLogicalDisplayMapper.getDisplayLocked(device2)
.getDisplayInfoLocked().thermalBrightnessThrottlingDataId);
- mLogicalDisplayMapper.setDeviceStateLocked(2);
+ mLogicalDisplayMapper.setDeviceStateLocked(DEVICE_STATE_OPEN);
advanceTime(1000);
assertFalse(mLogicalDisplayMapper.getDisplayLocked(device1).isEnabledLocked());
assertTrue(mLogicalDisplayMapper.getDisplayLocked(device2).isEnabledLocked());
@@ -1043,7 +1049,7 @@ public class LogicalDisplayMapperTest {
// 3) Send DISPLAY_DEVICE_EVENT_CHANGE to inform the mapper of the new display state
// 4) Dispatch handler events.
mLogicalDisplayMapper.onBootCompleted();
- mLogicalDisplayMapper.setDeviceStateLocked(0);
+ mLogicalDisplayMapper.setDeviceStateLocked(DEVICE_STATE_CLOSED);
mDisplayDeviceRepo.onDisplayDeviceEvent(device3, DISPLAY_DEVICE_EVENT_CHANGED);
advanceTime(1000);
final int[] allDisplayIds = mLogicalDisplayMapper.getDisplayIdsLocked(
@@ -1073,7 +1079,7 @@ public class LogicalDisplayMapperTest {
/* includeDisabled= */ false));
// Now do it again to go back to state 1
- mLogicalDisplayMapper.setDeviceStateLocked(1);
+ mLogicalDisplayMapper.setDeviceStateLocked(DEVICE_STATE_HALF_OPEN);
mDisplayDeviceRepo.onDisplayDeviceEvent(device3, DISPLAY_DEVICE_EVENT_CHANGED);
advanceTime(1000);
final int[] threeDisplaysEnabled = mLogicalDisplayMapper.getDisplayIdsLocked(
@@ -1127,7 +1133,7 @@ public class LogicalDisplayMapperTest {
// We can only have one default display
assertEquals(DEFAULT_DISPLAY, id(display1));
- mLogicalDisplayMapper.setDeviceStateLocked(0);
+ mLogicalDisplayMapper.setDeviceStateLocked(DEVICE_STATE_CLOSED);
advanceTime(1000);
mLogicalDisplayMapper.onBootCompleted();
advanceTime(1000);
@@ -1180,13 +1186,15 @@ public class LogicalDisplayMapperTest {
Layout layout = new Layout();
createDefaultDisplay(layout, outer);
createNonDefaultDisplay(layout, inner, /* enabled= */ false, /* group= */ null);
- when(mDeviceStateToLayoutMapSpy.get(DEVICE_STATE_CLOSED)).thenReturn(layout);
+ when(mDeviceStateToLayoutMapSpy.get(DEVICE_STATE_CLOSED.getIdentifier())).thenReturn(
+ layout);
layout = new Layout();
createNonDefaultDisplay(layout, outer, /* enabled= */ false, /* group= */ null);
createDefaultDisplay(layout, inner);
- when(mDeviceStateToLayoutMapSpy.get(DEVICE_STATE_HALF_OPEN)).thenReturn(layout);
- when(mDeviceStateToLayoutMapSpy.get(DEVICE_STATE_OPEN)).thenReturn(layout);
+ when(mDeviceStateToLayoutMapSpy.get(DEVICE_STATE_HALF_OPEN.getIdentifier())).thenReturn(
+ layout);
+ when(mDeviceStateToLayoutMapSpy.get(DEVICE_STATE_OPEN.getIdentifier())).thenReturn(layout);
when(mDeviceStateToLayoutMapSpy.size()).thenReturn(4);
add(outer);
@@ -1317,6 +1325,15 @@ public class LogicalDisplayMapperTest {
assertNotEquals(DEFAULT_DISPLAY, id(displayRemoved));
}
+ private static DeviceState createDeviceState(int identifier, @NonNull String name,
+ @NonNull Set<@DeviceState.SystemDeviceStateProperties Integer> systemProperties,
+ @NonNull Set<@DeviceState.PhysicalDeviceStateProperties Integer> physicalProperties) {
+ DeviceState.Configuration deviceStateConfiguration = new DeviceState.Configuration.Builder(
+ identifier, name).setSystemProperties(systemProperties).setPhysicalProperties(
+ physicalProperties).build();
+ return new DeviceState(deviceStateConfiguration);
+ }
+
private final static class FoldableDisplayDevices {
final TestDisplayDevice mOuter;
final TestDisplayDevice mInner;
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/HdrClamperTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/HdrClamperTest.java
index c785ea6b1865..721285636d7a 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/HdrClamperTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/HdrClamperTest.java
@@ -34,6 +34,7 @@ import android.os.PowerManager;
import androidx.test.filters.SmallTest;
import com.android.server.display.AutomaticBrightnessController;
+import com.android.server.display.config.DisplayDeviceConfigTestUtilsKt;
import com.android.server.display.config.HdrBrightnessData;
import com.android.server.testutils.OffsettableClock;
import com.android.server.testutils.TestHandler;
@@ -54,13 +55,14 @@ public class HdrClamperTest {
private static final float FLOAT_TOLERANCE = 0.0001f;
private static final long SEND_TIME_TOLERANCE = 100;
- private static final HdrBrightnessData TEST_HDR_DATA = new HdrBrightnessData(
- Map.of(500f, 0.6f),
- /* brightnessIncreaseDebounceMillis= */ 1000,
- /* screenBrightnessRampIncrease= */ 0.02f,
- /* brightnessDecreaseDebounceMillis= */ 3000,
- /* screenBrightnessRampDecrease= */0.04f
- );
+ private static final HdrBrightnessData TEST_HDR_DATA = DisplayDeviceConfigTestUtilsKt
+ .createHdrBrightnessData(
+ Map.of(500f, 0.6f),
+ /* brightnessIncreaseDebounceMillis= */ 1000,
+ /* screenBrightnessRampIncrease= */ 0.02f,
+ /* brightnessDecreaseDebounceMillis= */ 3000,
+ /* screenBrightnessRampDecrease= */0.04f
+ );
private static final int WIDTH = 600;
private static final int HEIGHT = 800;
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutoBrightnessFallbackStrategyTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutoBrightnessFallbackStrategyTest.java
index 4d5ff55cc805..bb24c0f7b18e 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutoBrightnessFallbackStrategyTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutoBrightnessFallbackStrategyTest.java
@@ -110,7 +110,6 @@ public class AutoBrightnessFallbackStrategyTest {
new DisplayBrightnessState.Builder()
.setBrightness(fallbackBrightness)
.setBrightnessReason(brightnessReason)
- .setSdrBrightness(fallbackBrightness)
.setDisplayBrightnessStrategyName(mAutoBrightnessFallbackStrategy.getName())
.build();
DisplayBrightnessState updatedDisplayBrightnessState =
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java
index e16377e57321..93ff9e11d52f 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java
@@ -559,7 +559,6 @@ public class AutomaticBrightnessStrategyTest {
mock(DisplayManagerInternal.DisplayPowerRequest.class);
DisplayBrightnessState expectedDisplayBrightnessState = new DisplayBrightnessState.Builder()
.setBrightness(brightness)
- .setSdrBrightness(brightness)
.setBrightnessReason(brightnessReason)
.setDisplayBrightnessStrategyName(mAutomaticBrightnessStrategy.getName())
.setIsSlowChange(false)
@@ -608,7 +607,6 @@ public class AutomaticBrightnessStrategyTest {
DisplayBrightnessState expectedDisplayBrightnessState = new DisplayBrightnessState.Builder()
.setBrightness(brightness)
- .setSdrBrightness(brightness)
.setBrightnessReason(brightnessReason)
.setDisplayBrightnessStrategyName(mAutomaticBrightnessStrategy.getName())
.setIsSlowChange(false)
@@ -648,7 +646,6 @@ public class AutomaticBrightnessStrategyTest {
DisplayBrightnessState expectedDisplayBrightnessState = new DisplayBrightnessState.Builder()
.setBrightness(brightness)
- .setSdrBrightness(brightness)
.setBrightnessReason(brightnessReason)
.setDisplayBrightnessStrategyName(mAutomaticBrightnessStrategy.getName())
.setIsSlowChange(true)
@@ -688,7 +685,6 @@ public class AutomaticBrightnessStrategyTest {
DisplayBrightnessState expectedDisplayBrightnessState = new DisplayBrightnessState.Builder()
.setBrightness(brightness)
- .setSdrBrightness(brightness)
.setBrightnessReason(brightnessReason)
.setDisplayBrightnessStrategyName(mAutomaticBrightnessStrategy.getName())
.setIsSlowChange(false)
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/BoostBrightnessStrategyTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/BoostBrightnessStrategyTest.java
index 353432539587..275bb3efee8e 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/BoostBrightnessStrategyTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/BoostBrightnessStrategyTest.java
@@ -55,7 +55,6 @@ public class BoostBrightnessStrategyTest {
new DisplayBrightnessState.Builder()
.setBrightness(PowerManager.BRIGHTNESS_MAX)
.setBrightnessReason(brightnessReason)
- .setSdrBrightness(PowerManager.BRIGHTNESS_MAX)
.setDisplayBrightnessStrategyName(mBoostBrightnessStrategy.getName())
.build();
DisplayBrightnessState updatedDisplayBrightnessState =
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/DozeBrightnessStrategyTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/DozeBrightnessStrategyTest.java
index bd6d8be45fcb..23e447c25245 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/DozeBrightnessStrategyTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/DozeBrightnessStrategyTest.java
@@ -52,7 +52,6 @@ public class DozeBrightnessStrategyTest {
new DisplayBrightnessState.Builder()
.setBrightness(dozeScreenBrightness)
.setBrightnessReason(brightnessReason)
- .setSdrBrightness(dozeScreenBrightness)
.setDisplayBrightnessStrategyName(mDozeBrightnessModeStrategy.getName())
.build();
DisplayBrightnessState updatedDisplayBrightnessState =
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/FallbackBrightnessStrategyTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/FallbackBrightnessStrategyTest.java
index 4cae35d11853..c4a579092d38 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/FallbackBrightnessStrategyTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/FallbackBrightnessStrategyTest.java
@@ -54,7 +54,6 @@ public class FallbackBrightnessStrategyTest {
new DisplayBrightnessState.Builder()
.setBrightness(currentBrightness)
.setBrightnessReason(brightnessReason)
- .setSdrBrightness(currentBrightness)
.setDisplayBrightnessStrategyName(mFallbackBrightnessStrategy.getName())
.setShouldUpdateScreenBrightnessSetting(true)
.setIsUserInitiatedChange(true)
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/FollowerBrightnessStrategyTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/FollowerBrightnessStrategyTest.java
index fdaf8f6a7808..c01f96e800de 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/FollowerBrightnessStrategyTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/FollowerBrightnessStrategyTest.java
@@ -55,7 +55,6 @@ public class FollowerBrightnessStrategyTest {
new DisplayBrightnessState.Builder()
.setBrightness(brightnessToFollow)
.setBrightnessReason(brightnessReason)
- .setSdrBrightness(brightnessToFollow)
.setDisplayBrightnessStrategyName(mFollowerBrightnessStrategy.getName())
.setIsSlowChange(slowChange)
.build();
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/OffloadBrightnessStrategyTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/OffloadBrightnessStrategyTest.java
index e3c276025e51..9fb2afa26ed2 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/OffloadBrightnessStrategyTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/OffloadBrightnessStrategyTest.java
@@ -66,7 +66,6 @@ public class OffloadBrightnessStrategyTest {
new DisplayBrightnessState.Builder()
.setBrightness(brightness)
.setBrightnessReason(brightnessReason)
- .setSdrBrightness(brightness)
.setDisplayBrightnessStrategyName(mOffloadBrightnessStrategy.getName())
.setShouldUpdateScreenBrightnessSetting(true)
.build();
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/OverrideBrightnessStrategyTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/OverrideBrightnessStrategyTest.java
index ebe407b2445b..e8b4c06b9c89 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/OverrideBrightnessStrategyTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/OverrideBrightnessStrategyTest.java
@@ -55,7 +55,6 @@ public class OverrideBrightnessStrategyTest {
new DisplayBrightnessState.Builder()
.setBrightness(overrideBrightness)
.setBrightnessReason(brightnessReason)
- .setSdrBrightness(overrideBrightness)
.setDisplayBrightnessStrategyName(mOverrideBrightnessStrategy.getName())
.build();
DisplayBrightnessState updatedDisplayBrightnessState =
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/ScreenOffBrightnessStrategyTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/ScreenOffBrightnessStrategyTest.java
index 4bad5696861f..38709ece7007 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/ScreenOffBrightnessStrategyTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/ScreenOffBrightnessStrategyTest.java
@@ -51,7 +51,6 @@ public final class ScreenOffBrightnessStrategyTest {
DisplayBrightnessState expectedDisplayBrightnessState =
new DisplayBrightnessState.Builder()
.setBrightness(PowerManager.BRIGHTNESS_OFF_FLOAT)
- .setSdrBrightness(PowerManager.BRIGHTNESS_OFF_FLOAT)
.setBrightnessReason(brightnessReason)
.setDisplayBrightnessStrategyName(mScreenOffBrightnessModeStrategy
.getName())
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/TemporaryBrightnessStrategyTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/TemporaryBrightnessStrategyTest.java
index 5410a20e9d75..f523b6af426b 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/TemporaryBrightnessStrategyTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/TemporaryBrightnessStrategyTest.java
@@ -55,7 +55,6 @@ public class TemporaryBrightnessStrategyTest {
new DisplayBrightnessState.Builder()
.setBrightness(temporaryBrightness)
.setBrightnessReason(brightnessReason)
- .setSdrBrightness(temporaryBrightness)
.setDisplayBrightnessStrategyName(mTemporaryBrightnessStrategy.getName())
.build();
DisplayBrightnessState updatedDisplayBrightnessState =
diff --git a/services/tests/displayservicetests/src/com/android/server/display/config/DisplayDeviceConfigTestUtils.kt b/services/tests/displayservicetests/src/com/android/server/display/config/DisplayDeviceConfigTestUtils.kt
new file mode 100644
index 000000000000..3b3d6f74da50
--- /dev/null
+++ b/services/tests/displayservicetests/src/com/android/server/display/config/DisplayDeviceConfigTestUtils.kt
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.config
+
+import android.util.Spline
+import android.util.Xml
+import com.android.server.display.config.HighBrightnessModeData.HDR_PERCENT_OF_SCREEN_REQUIRED_DEFAULT
+import java.io.ByteArrayInputStream
+import java.io.ByteArrayOutputStream
+import java.io.OutputStreamWriter
+import org.xmlpull.v1.XmlSerializer
+
+fun createRefreshRateData(
+ defaultRefreshRate: Int = 60,
+ defaultPeakRefreshRate: Int = 60,
+ defaultRefreshRateInHbmHdr: Int = 60,
+ defaultRefreshRateInHbmSunlight: Int = 60,
+ lowPowerSupportedModes: List<SupportedModeData> = emptyList(),
+ lowLightBlockingZoneSupportedModes: List<SupportedModeData> = emptyList()
+): RefreshRateData {
+ return RefreshRateData(
+ defaultRefreshRate, defaultPeakRefreshRate,
+ defaultRefreshRateInHbmHdr, defaultRefreshRateInHbmSunlight,
+ lowPowerSupportedModes, lowLightBlockingZoneSupportedModes
+ )
+}
+
+@JvmOverloads
+fun createHdrBrightnessData(
+ maxBrightnessLimits: Map<Float, Float> = mapOf(Pair(500f, 0.6f)),
+ brightnessIncreaseDebounceMillis: Long = 1000,
+ screenBrightnessRampIncrease: Float = 0.02f,
+ brightnessDecreaseDebounceMillis: Long = 3000,
+ screenBrightnessRampDecrease: Float = 0.04f,
+ minimumHdrPercentOfScreenForNbm: Float = HDR_PERCENT_OF_SCREEN_REQUIRED_DEFAULT,
+ minimumHdrPercentOfScreenForHbm: Float = HDR_PERCENT_OF_SCREEN_REQUIRED_DEFAULT,
+ allowInLowPowerMode: Boolean = false,
+ sdrToHdrRatioSpline: Spline? = null
+): HdrBrightnessData {
+ return HdrBrightnessData(
+ maxBrightnessLimits,
+ brightnessIncreaseDebounceMillis,
+ screenBrightnessRampIncrease,
+ brightnessDecreaseDebounceMillis,
+ screenBrightnessRampDecrease,
+ minimumHdrPercentOfScreenForNbm,
+ minimumHdrPercentOfScreenForHbm,
+ allowInLowPowerMode,
+ sdrToHdrRatioSpline
+ )
+}
+
+fun XmlSerializer.highBrightnessMode(
+ enabled: String = "true",
+ transitionPoint: String = "0.67",
+ minimumLux: String = "2500",
+ timeWindowSecs: String = "200",
+ timeMaxSecs: String = "30",
+ timeMinSecs: String = "3",
+ refreshRateRange: Pair<String, String>? = null,
+ allowInLowPowerMode: String? = null,
+ minimumHdrPercentOfScreen: String? = null,
+ sdrHdrRatioMap: List<Pair<String, String>>? = null,
+) {
+ element("highBrightnessMode") {
+ attribute("", "enabled", enabled)
+ element("transitionPoint", transitionPoint)
+ element("minimumLux", minimumLux)
+ element("timing") {
+ element("timeWindowSecs", timeWindowSecs)
+ element("timeMaxSecs", timeMaxSecs)
+ element("timeMinSecs", timeMinSecs)
+ }
+ pair("refreshRate", "minimum", "maximum", refreshRateRange)
+ element("allowInLowPowerMode", allowInLowPowerMode)
+ element("minimumHdrPercentOfScreen", minimumHdrPercentOfScreen)
+ map("sdrHdrRatioMap", "point", "sdrNits", "hdrRatio", sdrHdrRatioMap)
+ }
+}
+
+fun XmlSerializer.hdrBrightnessConfig(
+ brightnessMap: List<Pair<String, String>> = listOf(Pair("500", "0.6")),
+ brightnessIncreaseDebounceMillis: String = "1000",
+ screenBrightnessRampIncrease: String = "0.02",
+ brightnessDecreaseDebounceMillis: String = "3000",
+ screenBrightnessRampDecrease: String = "0.04",
+ minimumHdrPercentOfScreenForNbm: String? = null,
+ minimumHdrPercentOfScreenForHbm: String? = null,
+ allowInLowPowerMode: String? = null,
+ sdrHdrRatioMap: List<Pair<String, String>>? = null,
+) {
+ element("hdrBrightnessConfig") {
+ map("brightnessMap", "point", "first", "second", brightnessMap)
+ element("brightnessIncreaseDebounceMillis", brightnessIncreaseDebounceMillis)
+ element("screenBrightnessRampIncrease", screenBrightnessRampIncrease)
+ element("brightnessDecreaseDebounceMillis", brightnessDecreaseDebounceMillis)
+ element("screenBrightnessRampDecrease", screenBrightnessRampDecrease)
+ element("minimumHdrPercentOfScreenForNbm", minimumHdrPercentOfScreenForNbm)
+ element("minimumHdrPercentOfScreenForHbm", minimumHdrPercentOfScreenForHbm)
+ element("allowInLowPowerMode", allowInLowPowerMode)
+ map("sdrHdrRatioMap", "point", "first", "second", sdrHdrRatioMap)
+ }
+}
+
+fun createDisplayConfiguration(content: XmlSerializer.() -> Unit = { }): DisplayConfiguration {
+ val byteArrayOutputStream = ByteArrayOutputStream()
+ val xmlSerializer = Xml.newSerializer()
+ OutputStreamWriter(byteArrayOutputStream).use { writer ->
+ xmlSerializer.setOutput(writer)
+ xmlSerializer.startDocument("UTF-8", true)
+ xmlSerializer.startTag("", "displayConfiguration")
+ xmlSerializer.content()
+ xmlSerializer.endTag("", "displayConfiguration")
+ xmlSerializer.endDocument()
+ }
+ return XmlParser.read(ByteArrayInputStream(byteArrayOutputStream.toByteArray()))
+}
+
+private fun XmlSerializer.map(
+ rootName: String,
+ nodeName: String,
+ keyName: String,
+ valueName: String,
+ map: List<Pair<String, String>>?
+) {
+ map?.let { m ->
+ element(rootName) {
+ m.forEach { e -> pair(nodeName, keyName, valueName, e) }
+ }
+ }
+}
+
+private fun XmlSerializer.pair(
+ nodeName: String,
+ keyName: String,
+ valueName: String,
+ pair: Pair<String, String>?
+) {
+ pair?.let {
+ element(nodeName) {
+ element(keyName, pair.first)
+ element(valueName, pair.second)
+ }
+ }
+}
+
+private fun XmlSerializer.element(name: String, content: String?) {
+ if (content != null) {
+ startTag("", name)
+ text(content)
+ endTag("", name)
+ }
+}
+
+private fun XmlSerializer.element(name: String, content: XmlSerializer.() -> Unit) {
+ startTag("", name)
+ content()
+ endTag("", name)
+} \ No newline at end of file
diff --git a/services/tests/displayservicetests/src/com/android/server/display/config/HdrBrightnessDataTest.kt b/services/tests/displayservicetests/src/com/android/server/display/config/HdrBrightnessDataTest.kt
new file mode 100644
index 000000000000..19c6924dfa5b
--- /dev/null
+++ b/services/tests/displayservicetests/src/com/android/server/display/config/HdrBrightnessDataTest.kt
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.config
+
+import android.util.Spline.createSpline
+import androidx.test.filters.SmallTest
+import com.android.server.display.DisplayBrightnessState
+import com.android.server.display.config.HighBrightnessModeData.HDR_PERCENT_OF_SCREEN_REQUIRED_DEFAULT
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+
+@SmallTest
+class HdrBrightnessDataTest {
+
+ @Test
+ fun `test HdrBrightnessData default configuration`() {
+ val displayConfiguration = createDisplayConfiguration {
+ hdrBrightnessConfig(
+ brightnessDecreaseDebounceMillis = "3000",
+ screenBrightnessRampDecrease = "0.05",
+ brightnessIncreaseDebounceMillis = "2000",
+ screenBrightnessRampIncrease = "0.03",
+ brightnessMap = listOf(Pair("500", "0.6"), Pair("600", "0.7")),
+ minimumHdrPercentOfScreenForNbm = null,
+ minimumHdrPercentOfScreenForHbm = null,
+ allowInLowPowerMode = null,
+ sdrHdrRatioMap = null,
+ )
+ }
+
+ val hdrBrightnessData = HdrBrightnessData.loadConfig(displayConfiguration)
+ assertThat(hdrBrightnessData).isNotNull()
+
+ assertThat(hdrBrightnessData!!.brightnessDecreaseDebounceMillis).isEqualTo(3000)
+ assertThat(hdrBrightnessData.screenBrightnessRampDecrease).isEqualTo(0.05f)
+ assertThat(hdrBrightnessData.brightnessIncreaseDebounceMillis).isEqualTo(2000)
+ assertThat(hdrBrightnessData.screenBrightnessRampIncrease).isEqualTo(0.03f)
+
+ assertThat(hdrBrightnessData.maxBrightnessLimits).hasSize(2)
+ assertThat(hdrBrightnessData.maxBrightnessLimits).containsEntry(500f, 0.6f)
+ assertThat(hdrBrightnessData.maxBrightnessLimits).containsEntry(600f, 0.7f)
+
+ assertThat(hdrBrightnessData.minimumHdrPercentOfScreenForNbm).isEqualTo(
+ HDR_PERCENT_OF_SCREEN_REQUIRED_DEFAULT
+ )
+ assertThat(hdrBrightnessData.minimumHdrPercentOfScreenForHbm).isEqualTo(
+ HDR_PERCENT_OF_SCREEN_REQUIRED_DEFAULT
+ )
+ assertThat(hdrBrightnessData.allowInLowPowerMode).isFalse()
+ assertThat(hdrBrightnessData.sdrToHdrRatioSpline).isNull()
+ }
+
+ @Test
+ fun `test HdrBrightnessData fallback configuration`() {
+ val displayConfiguration = createDisplayConfiguration {
+ hdrBrightnessConfig(
+ minimumHdrPercentOfScreenForNbm = null,
+ minimumHdrPercentOfScreenForHbm = null,
+ allowInLowPowerMode = null,
+ sdrHdrRatioMap = null,
+ )
+ highBrightnessMode(
+ minimumHdrPercentOfScreen = "0.2",
+ sdrHdrRatioMap = listOf(Pair("2.0", "4.0"), Pair("5.0", "8.0"))
+ )
+ }
+
+ val hdrBrightnessData = HdrBrightnessData.loadConfig(displayConfiguration)
+ assertThat(hdrBrightnessData).isNotNull()
+
+ assertThat(hdrBrightnessData!!.minimumHdrPercentOfScreenForNbm).isEqualTo(0.2f)
+ assertThat(hdrBrightnessData.minimumHdrPercentOfScreenForHbm).isEqualTo(0.2f)
+ assertThat(hdrBrightnessData.allowInLowPowerMode).isFalse()
+
+ val expectedSpline = createSpline(floatArrayOf(2.0f, 5.0f), floatArrayOf(4.0f, 8.0f))
+ assertThat(hdrBrightnessData.sdrToHdrRatioSpline.toString())
+ .isEqualTo(expectedSpline.toString())
+ }
+
+ @Test
+ fun `test HdrBrightnessData fallback configuration no hdrBrightnessConfig`() {
+ val displayConfiguration = createDisplayConfiguration {
+ highBrightnessMode(
+ minimumHdrPercentOfScreen = "0.2",
+ sdrHdrRatioMap = listOf(Pair("2.0", "4.0"), Pair("5.0", "8.0"))
+ )
+ }
+
+ val hdrBrightnessData = HdrBrightnessData.loadConfig(displayConfiguration)
+ assertThat(hdrBrightnessData).isNotNull()
+
+ assertThat(hdrBrightnessData!!.brightnessDecreaseDebounceMillis).isEqualTo(0)
+ assertThat(hdrBrightnessData.screenBrightnessRampDecrease)
+ .isEqualTo(DisplayBrightnessState.CUSTOM_ANIMATION_RATE_NOT_SET)
+ assertThat(hdrBrightnessData.brightnessIncreaseDebounceMillis).isEqualTo(0)
+ assertThat(hdrBrightnessData.screenBrightnessRampIncrease)
+ .isEqualTo(DisplayBrightnessState.CUSTOM_ANIMATION_RATE_NOT_SET)
+
+ assertThat(hdrBrightnessData.maxBrightnessLimits).hasSize(0)
+
+ assertThat(hdrBrightnessData.minimumHdrPercentOfScreenForNbm).isEqualTo(0.2f)
+ assertThat(hdrBrightnessData.minimumHdrPercentOfScreenForHbm).isEqualTo(0.2f)
+ assertThat(hdrBrightnessData.allowInLowPowerMode).isFalse()
+
+ val expectedSpline = createSpline(floatArrayOf(2.0f, 5.0f), floatArrayOf(4.0f, 8.0f))
+ assertThat(hdrBrightnessData.sdrToHdrRatioSpline.toString())
+ .isEqualTo(expectedSpline.toString())
+ }
+
+ @Test
+ fun `test HdrBrightnessData configuration no configuration`() {
+ val displayConfiguration = createDisplayConfiguration()
+
+ val hdrBrightnessData = HdrBrightnessData.loadConfig(displayConfiguration)
+ assertThat(hdrBrightnessData).isNull()
+ }
+
+ @Test
+ fun `test HdrBrightnessData real configuration`() {
+ val displayConfiguration = createDisplayConfiguration {
+ hdrBrightnessConfig(
+ minimumHdrPercentOfScreenForNbm = "0.3",
+ minimumHdrPercentOfScreenForHbm = "0.6",
+ allowInLowPowerMode = "true",
+ sdrHdrRatioMap = listOf(Pair("3.0", "5.0"), Pair("6.0", "8.0"))
+ )
+ highBrightnessMode(
+ minimumHdrPercentOfScreen = "0.2",
+ sdrHdrRatioMap = listOf(Pair("2.0", "4.0"), Pair("5.0", "8.0"))
+ )
+ }
+
+ val hdrBrightnessData = HdrBrightnessData.loadConfig(displayConfiguration)
+ assertThat(hdrBrightnessData).isNotNull()
+
+ assertThat(hdrBrightnessData!!.minimumHdrPercentOfScreenForNbm).isEqualTo(0.3f)
+ assertThat(hdrBrightnessData.minimumHdrPercentOfScreenForHbm).isEqualTo(0.6f)
+ assertThat(hdrBrightnessData.allowInLowPowerMode).isTrue()
+
+ val expectedSpline = createSpline(floatArrayOf(3.0f, 6.0f), floatArrayOf(5.0f, 8.0f))
+ assertThat(hdrBrightnessData.sdrToHdrRatioSpline.toString())
+ .isEqualTo(expectedSpline.toString())
+ }
+} \ No newline at end of file
diff --git a/services/tests/displayservicetests/src/com/android/server/display/mode/BrightnessObserverTest.kt b/services/tests/displayservicetests/src/com/android/server/display/mode/BrightnessObserverTest.kt
index 95702aa1bce1..3c77ec925078 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/mode/BrightnessObserverTest.kt
+++ b/services/tests/displayservicetests/src/com/android/server/display/mode/BrightnessObserverTest.kt
@@ -25,6 +25,7 @@ import androidx.test.filters.SmallTest
import com.android.server.display.DisplayDeviceConfig
import com.android.server.display.config.RefreshRateData
import com.android.server.display.config.SupportedModeData
+import com.android.server.display.config.createRefreshRateData
import com.android.server.display.feature.DisplayManagerFlags
import com.android.server.display.mode.DisplayModeDirector.DisplayDeviceConfigProvider
import com.android.server.testutils.TestHandler
diff --git a/services/tests/displayservicetests/src/com/android/server/display/mode/SettingsObserverTest.kt b/services/tests/displayservicetests/src/com/android/server/display/mode/SettingsObserverTest.kt
index e431c8c3555c..4fc574a77571 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/mode/SettingsObserverTest.kt
+++ b/services/tests/displayservicetests/src/com/android/server/display/mode/SettingsObserverTest.kt
@@ -29,6 +29,7 @@ import com.android.internal.util.test.FakeSettingsProvider
import com.android.server.display.DisplayDeviceConfig
import com.android.server.display.config.RefreshRateData
import com.android.server.display.config.SupportedModeData
+import com.android.server.display.config.createRefreshRateData
import com.android.server.display.feature.DisplayManagerFlags
import com.android.server.display.mode.DisplayModeDirector.DisplayDeviceConfigProvider
import com.android.server.display.mode.SupportedRefreshRatesVote.RefreshRates
diff --git a/services/tests/displayservicetests/src/com/android/server/display/mode/TestUtils.kt b/services/tests/displayservicetests/src/com/android/server/display/mode/TestUtils.kt
index 5b07166d63e4..0b34fce18a1b 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/mode/TestUtils.kt
+++ b/services/tests/displayservicetests/src/com/android/server/display/mode/TestUtils.kt
@@ -16,9 +16,6 @@
package com.android.server.display.mode
-import com.android.server.display.config.RefreshRateData
-import com.android.server.display.config.SupportedModeData
-
internal fun createVotesSummary(
isDisplayResolutionRangeVotingEnabled: Boolean = true,
supportedModesVoteEnabled: Boolean = true,
@@ -29,15 +26,3 @@ internal fun createVotesSummary(
loggingEnabled, supportsFrameRateOverride)
}
-fun createRefreshRateData(
- defaultRefreshRate: Int = 60,
- defaultPeakRefreshRate: Int = 60,
- defaultRefreshRateInHbmHdr: Int = 60,
- defaultRefreshRateInHbmSunlight: Int = 60,
- lowPowerSupportedModes: List<SupportedModeData> = emptyList(),
- lowLightBlockingZoneSupportedModes: List<SupportedModeData> = emptyList()
-): RefreshRateData {
- return RefreshRateData(defaultRefreshRate, defaultPeakRefreshRate,
- defaultRefreshRateInHbmHdr, defaultRefreshRateInHbmSunlight,
- lowPowerSupportedModes, lowLightBlockingZoneSupportedModes)
-}
diff --git a/services/tests/mockingservicestests/Android.bp b/services/tests/mockingservicestests/Android.bp
index 4149e44a2ee9..5b2c0c651058 100644
--- a/services/tests/mockingservicestests/Android.bp
+++ b/services/tests/mockingservicestests/Android.bp
@@ -53,6 +53,7 @@ android_test {
"mockingservicestests-utils-mockito",
"mockito-target-extended-minus-junit4",
"platform-compat-test-rules",
+ "platform-parametric-runner-lib",
"platform-test-annotations",
"PlatformProperties",
"service-blobstore",
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java
index 419bcb8650a7..e610a32cb549 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java
@@ -527,7 +527,7 @@ public class ActivityManagerServiceTest {
final ProcessRecord appRec = new ProcessRecord(mAms, info, info.processName, uid);
final ProcessStatsService tracker = mAms.mProcessStats;
- final IApplicationThread appThread = mock(IApplicationThread.class);
+ final ApplicationThreadDeferred appThread = mock(ApplicationThreadDeferred.class);
doReturn(mock(IBinder.class)).when(appThread).asBinder();
appRec.makeActive(appThread, tracker);
mAms.mProcessList.addProcessNameLocked(appRec);
@@ -701,7 +701,8 @@ public class ActivityManagerServiceTest {
final var wpc = fifoProc.getWindowProcessController();
spyOn(wpc);
doReturn(true).when(wpc).useFifoUiScheduling();
- fifoProc.makeActive(fifoProc.getThread(), mAms.mProcessStats);
+ fifoProc.makeActive(new ApplicationThreadDeferred(fifoProc.getThread()),
+ mAms.mProcessStats);
assertTrue(fifoProc.useFifoUiScheduling());
assertTrue(mAms.mSpecifiedFifoProcesses.contains(fifoProc));
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ApplicationThreadDeferredTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ApplicationThreadDeferredTest.java
new file mode 100644
index 000000000000..8f8c1ac51907
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/am/ApplicationThreadDeferredTest.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.am;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.app.IApplicationThread;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+
+
+/**
+ * Tests to verify that the ApplicationThreadDeferred properly defers binder calls to paused
+ * processes.
+ */
+@SmallTest
+public class ApplicationThreadDeferredTest {
+ private static final String TAG = "ApplicationThreadDeferredTest";
+
+ private void callDeferredApis(IApplicationThread thread) throws Exception {
+ thread.clearDnsCache();
+ thread.updateHttpProxy();
+ thread.updateTimeZone();
+ thread.scheduleLowMemory();
+ }
+
+ // Verify that the special APIs have been called count times.
+ private void verifyDeferredApis(IApplicationThread thread, int count) throws Exception {
+ verify(thread, times(count)).clearDnsCache();
+ verify(thread, times(count)).updateHttpProxy();
+ verify(thread, times(count)).updateTimeZone();
+ verify(thread, times(count)).scheduleLowMemory();
+ }
+
+ // Test the baseline behavior of IApplicationThread. If this test fails, all other tests are
+ // suspect.
+ @Test
+ public void testBaseline() throws Exception {
+ IApplicationThread thread = mock(IApplicationThread.class);
+ callDeferredApis(thread);
+ verifyDeferredApis(thread, 1);
+ }
+
+ // Test the baseline behavior of IApplicationThreadDeferred. If this test fails, all other
+ // tests are suspect.
+ @Test
+ public void testBaselineDeferred() throws Exception {
+ IApplicationThread thread = mock(ApplicationThreadDeferred.class);
+ callDeferredApis(thread);
+ verifyDeferredApis(thread, 1);
+ }
+
+ // Verify that a deferred thread behaves like a regular thread when it is not paused.
+ @Test
+ public void testDeferredUnpaused() throws Exception {
+ IApplicationThread base = mock(IApplicationThread.class);
+ ApplicationThreadDeferred thread = new ApplicationThreadDeferred(base, true);
+ callDeferredApis(thread);
+ verifyDeferredApis(base, 1);
+ }
+
+ // Verify that a paused deferred thread thread does not deliver any calls to its parent. Then
+ // unpause the thread and verify that the collapsed calls are forwarded.
+ @Test
+ public void testDeferredPaused() throws Exception {
+ IApplicationThread base = mock(IApplicationThread.class);
+ ApplicationThreadDeferred thread = new ApplicationThreadDeferred(base, true);
+ thread.onProcessPaused();
+ callDeferredApis(thread);
+ callDeferredApis(thread);
+ verifyDeferredApis(base, 0);
+ thread.onProcessUnpaused();
+ verifyDeferredApis(base, 1);
+ }
+
+ // TODO: [b/302724778] Remove manual JNI load
+ static {
+ System.loadLibrary("mockingservicestestjni");
+ }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/AsyncProcessStartTest.java b/services/tests/mockingservicestests/src/com/android/server/am/AsyncProcessStartTest.java
index 80f7a066985b..93066d8d113a 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/AsyncProcessStartTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/AsyncProcessStartTest.java
@@ -189,7 +189,7 @@ public class AsyncProcessStartTest {
private ProcessRecord makeActiveProcessRecord(ApplicationInfo ai, boolean wedge)
throws Exception {
- final IApplicationThread thread = mock(IApplicationThread.class);
+ final ApplicationThreadDeferred thread = mock(ApplicationThreadDeferred.class);
final IBinder threadBinder = new Binder();
doReturn(threadBinder).when(thread).asBinder();
doAnswer((invocation) -> {
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
index 13ba1e5e705c..3aaf2e5c61a6 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
@@ -325,13 +325,13 @@ public class BroadcastQueueTest extends BaseBroadcastQueueTest {
ProcessRecord.updateProcessRecordNodes(r);
mActiveProcesses.add(r);
- final IApplicationThread thread;
+ final ApplicationThreadDeferred thread;
if (dead) {
- thread = mock(IApplicationThread.class, (invocation) -> {
+ thread = mock(ApplicationThreadDeferred.class, (invocation) -> {
throw new DeadObjectException();
});
} else {
- thread = mock(IApplicationThread.class);
+ thread = mock(ApplicationThreadDeferred.class);
}
final IBinder threadBinder = new Binder();
doReturn(threadBinder).when(thread).asBinder();
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/CacheOomRankerTest.java b/services/tests/mockingservicestests/src/com/android/server/am/CacheOomRankerTest.java
index 240ddf51ffdc..0796f419e385 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/CacheOomRankerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/CacheOomRankerTest.java
@@ -760,7 +760,7 @@ public class CacheOomRankerTest {
ProcessStatsService processStatsService = new ProcessStatsService(
mock(ActivityManagerService.class), new File(Environment.getDataSystemCeDirectory(),
"procstats"));
- app.makeActive(mock(IApplicationThread.class), processStatsService);
+ app.makeActive(mock(ApplicationThreadDeferred.class), processStatsService);
return app;
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
index 6366f24a27e1..1dbd5320cac6 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
@@ -3209,7 +3209,7 @@ public class MockingOomAdjusterTests {
final ProcessReceiverRecord receivers = app.mReceivers;
final ProcessProfileRecord profile = app.mProfile;
final ProcessProviderRecord providers = app.mProviders;
- app.makeActive(mock(IApplicationThread.class), mService.mProcessStats);
+ app.makeActive(mock(ApplicationThreadDeferred.class), mService.mProcessStats);
app.setLastActivityTime(mLastActivityTime);
app.setKilledByAm(mKilledByAm);
app.setIsolatedEntryPoint(mIsolatedEntryPoint);
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ProcessObserverTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ProcessObserverTest.java
index 89c67d5e32b7..3572d2315a9d 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/ProcessObserverTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/ProcessObserverTest.java
@@ -193,7 +193,7 @@ public class ProcessObserverTest {
private ProcessRecord makeActiveProcessRecord(ApplicationInfo ai)
throws Exception {
- final IApplicationThread thread = mock(IApplicationThread.class);
+ final ApplicationThreadDeferred thread = mock(ApplicationThreadDeferred.class);
final IBinder threadBinder = new Binder();
doReturn(threadBinder).when(thread).asBinder();
doAnswer((invocation) -> {
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ServiceBindingOomAdjPolicyTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ServiceBindingOomAdjPolicyTest.java
index 5f126774835d..1ff4a27cb787 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/ServiceBindingOomAdjPolicyTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/ServiceBindingOomAdjPolicyTest.java
@@ -529,7 +529,7 @@ public final class ServiceBindingOomAdjPolicyTest {
@SuppressWarnings("GuardedBy")
private ProcessRecord addProcessRecord(int pid, int uid, int procState, int adj, int cap,
String packageName) {
- final IApplicationThread appThread = mock(IApplicationThread.class);
+ final ApplicationThreadDeferred appThread = mock(ApplicationThreadDeferred.class);
final IBinder threadBinder = mock(IBinder.class);
final ProcessRecord app = makeProcessRecord(pid, uid, uid, null, 0,
procState, adj, cap, 0L, 0L, packageName, packageName, mAms);
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ServiceTimeoutTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ServiceTimeoutTest.java
index 7ec27be0bfc3..3c4363651557 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/ServiceTimeoutTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/ServiceTimeoutTest.java
@@ -145,7 +145,7 @@ public final class ServiceTimeoutTest {
name, // processName
name, // packageName
mAms);
- app.makeActive(mock(IApplicationThread.class), mAms.mProcessStats);
+ app.makeActive(mock(ApplicationThreadDeferred.class), mAms.mProcessStats);
mProcessList.updateLruProcessLocked(app, false, null);
final long now = SystemClock.uptimeMillis();
diff --git a/services/tests/mockingservicestests/src/com/android/server/backup/utils/TarBackupReaderTest.java b/services/tests/mockingservicestests/src/com/android/server/backup/utils/TarBackupReaderTest.java
index 396f4da75172..bf7e3a0bd0a6 100644
--- a/services/tests/mockingservicestests/src/com/android/server/backup/utils/TarBackupReaderTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/backup/utils/TarBackupReaderTest.java
@@ -525,7 +525,7 @@ public class TarBackupReaderTest {
@Test
public void
- chooseRestorePolicy_flagOnNotRestoreAnyVersionVToURestoreAndInAllowlist_returnsIgnore()
+ chooseRestorePolicy_flagOnNotRestoreAnyVersionVToURestoreAndInAllowlist_returnsAccept()
throws Exception {
mSetFlagsRule.enableFlags(
@@ -540,7 +540,8 @@ public class TarBackupReaderTest {
FileMetadata info = new FileMetadata();
info.version = Build.VERSION_CODES.UPSIDE_DOWN_CAKE + 1;
- PackageInfo packageInfo = createNonRestoreAnyVersionUPackage();
+ PackageInfo packageInfo = createNonRestoreAnyVersionPackage(
+ Build.VERSION_CODES.UPSIDE_DOWN_CAKE);
PackageManagerStub.sPackageInfo = packageInfo;
doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(FAKE_SIGNATURE_1,
@@ -559,7 +560,7 @@ public class TarBackupReaderTest {
@Test
public void
- chooseRestorePolicy_flagOffNotRestoreAnyVersionVToURestoreAndInAllowlist_returnsAccept()
+ chooseRestorePolicy_flagOffNotRestoreAnyVersionVToURestoreAndInAllowlist_returnsIgnore()
throws Exception {
mSetFlagsRule.disableFlags(
@@ -574,7 +575,8 @@ public class TarBackupReaderTest {
FileMetadata info = new FileMetadata();
info.version = Build.VERSION_CODES.UPSIDE_DOWN_CAKE + 1;
- PackageInfo packageInfo = createNonRestoreAnyVersionUPackage();
+ PackageInfo packageInfo = createNonRestoreAnyVersionPackage(
+ Build.VERSION_CODES.UPSIDE_DOWN_CAKE);
PackageManagerStub.sPackageInfo = packageInfo;
doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(FAKE_SIGNATURE_1,
@@ -608,7 +610,8 @@ public class TarBackupReaderTest {
FileMetadata info = new FileMetadata();
info.version = Build.VERSION_CODES.UPSIDE_DOWN_CAKE + 1;
- PackageInfo packageInfo = createNonRestoreAnyVersionUPackage();
+ PackageInfo packageInfo = createNonRestoreAnyVersionPackage(
+ Build.VERSION_CODES.UPSIDE_DOWN_CAKE);
PackageManagerStub.sPackageInfo = packageInfo;
doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(FAKE_SIGNATURE_1,
@@ -716,6 +719,36 @@ public class TarBackupReaderTest {
LOG_EVENT_ID_VERSION_OF_BACKUP_OLDER);
}
+ @Test
+ public void
+ chooseRestorePolicy_allowlistNotSetNotRestoreAnyVersionVersionMismatch_returnsIgnore()
+ throws Exception {
+ mSetFlagsRule.disableFlags(
+ Flags.FLAG_ENABLE_V_TO_U_RESTORE_FOR_SYSTEM_COMPONENTS_IN_ALLOWLIST);
+
+ TarBackupReader tarBackupReader = createTarBackupReader();
+
+ Signature[] signatures = new Signature[]{FAKE_SIGNATURE_1};
+ FileMetadata info = new FileMetadata();
+ info.version = Build.VERSION_CODES.UPSIDE_DOWN_CAKE + 2;
+
+ PackageInfo packageInfo = createNonRestoreAnyVersionPackage(
+ Build.VERSION_CODES.UPSIDE_DOWN_CAKE + 1);
+ PackageManagerStub.sPackageInfo = packageInfo;
+
+ doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(FAKE_SIGNATURE_1,
+ packageInfo.packageName);
+ RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub,
+ false /* allowApks */, info, signatures, mMockPackageManagerInternal,
+ mUserId, mContext);
+
+ assertThat(policy).isEqualTo(RestorePolicy.IGNORE);
+ ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
+ verify(mBackupManagerMonitorMock).onEvent(bundleCaptor.capture());
+ assertThat(bundleCaptor.getValue().get(EXTRA_LOG_EVENT_ID)).isEqualTo(
+ LOG_EVENT_ID_VERSION_OF_BACKUP_OLDER);
+ }
+
private TarBackupReader createTarBackupReader() throws Exception {
InputStream inputStream = mContext.getResources().openRawResource(
R.raw.backup_telephony_no_password);
@@ -726,7 +759,7 @@ public class TarBackupReaderTest {
return tarBackupReader;
}
- private PackageInfo createNonRestoreAnyVersionUPackage(){
+ private PackageInfo createNonRestoreAnyVersionPackage(int versionCode) {
PackageInfo packageInfo = new PackageInfo();
packageInfo.packageName = "test";
packageInfo.applicationInfo = new ApplicationInfo();
@@ -740,7 +773,7 @@ public class TarBackupReaderTest {
SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
null,
null));
- packageInfo.versionCode = Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
+ packageInfo.versionCode = versionCode;
return packageInfo;
}
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/crashrecovery/Android.bp b/services/tests/mockingservicestests/src/com/android/server/crashrecovery/Android.bp
new file mode 100644
index 000000000000..127d3e8a4136
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/crashrecovery/Android.bp
@@ -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 {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+ default_team: "trendy_team_mainline_modularization",
+}
+
+android_test {
+ name: "CrashRecoveryModuleTests",
+
+ srcs: [
+ "*.java",
+ ],
+
+ static_libs: [
+ "androidx.test.core",
+ "androidx.test.runner",
+ "mockito-target-extended-minus-junit4",
+ "services.core",
+ "truth",
+ "flag-junit",
+ ],
+
+ libs: [
+ "android.test.mock",
+ "android.test.base",
+ "android.test.runner",
+ ],
+
+ jni_libs: [
+ "libdexmakerjvmtiagent",
+ "libstaticjvmtiagent",
+ ],
+
+ certificate: "platform",
+ platform_apis: true,
+ test_suites: [
+ "device-tests",
+ "automotive-tests",
+ ],
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/crashrecovery/AndroidManifest.xml b/services/tests/mockingservicestests/src/com/android/server/crashrecovery/AndroidManifest.xml
new file mode 100644
index 000000000000..067f116d003c
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/crashrecovery/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2024 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.server.crashrecovery">
+
+ <uses-sdk android:targetSdkVersion="35" />
+
+ <application android:testOnly="true"
+ android:debuggable="true">
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.server.crashrecovery"
+ android:label="Frameworks crashrecovery module test" />
+</manifest>
diff --git a/services/tests/mockingservicestests/src/com/android/server/crashrecovery/AndroidTest.xml b/services/tests/mockingservicestests/src/com/android/server/crashrecovery/AndroidTest.xml
new file mode 100644
index 000000000000..7b06ebec654d
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/crashrecovery/AndroidTest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2024 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<configuration description="Runs Crashrecovery Module Tests.">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-instrumentation" />
+
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="install-arg" value="-t" />
+ <option name="test-file-name" value="CrashRecoveryModuleTests.apk" />
+ </target_preparer>
+
+ <option name="test-tag" value="CrashRecoveryModuleTests" />
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="com.android.server.crashrecovery" />
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+ <option name="hidden-api-checks" value="false"/>
+ </test>
+</configuration>
diff --git a/services/tests/mockingservicestests/src/com/android/server/crashrecovery/CrashRecoveryModuleTest.java b/services/tests/mockingservicestests/src/com/android/server/crashrecovery/CrashRecoveryModuleTest.java
new file mode 100644
index 000000000000..c481f84719f4
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/crashrecovery/CrashRecoveryModuleTest.java
@@ -0,0 +1,103 @@
+/*
+ * 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.crashrecovery;
+
+import static com.android.server.SystemService.PHASE_ACTIVITY_MANAGER_READY;
+import static com.android.server.SystemService.PHASE_THIRD_PARTY_APPS_CAN_START;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.platform.test.flag.junit.SetFlagsRule;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.runner.AndroidJUnit4;
+
+
+import com.android.dx.mockito.inline.extended.ExtendedMockito;
+import com.android.server.PackageWatchdog;
+import com.android.server.RescueParty;
+import com.android.server.crashrecovery.CrashRecoveryModule.Lifecycle;
+
+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.Mockito;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
+
+/**
+ * Test CrashRecoveryModule.
+ */
+@RunWith(AndroidJUnit4.class)
+public class CrashRecoveryModuleTest {
+
+ @Rule
+ public SetFlagsRule mSetFlagsRule;
+
+ private MockitoSession mSession;
+ private Lifecycle mLifecycle;
+
+ @Mock PackageWatchdog mPackageWatchdog;
+
+ @Before
+ public void setup() {
+ Context context = ApplicationProvider.getApplicationContext();
+ mSession = ExtendedMockito.mockitoSession()
+ .initMocks(this)
+ .strictness(Strictness.LENIENT)
+ .mockStatic(PackageWatchdog.class)
+ .mockStatic(RescueParty.class)
+ .startMocking();
+ when(PackageWatchdog.getInstance(context)).thenReturn(mPackageWatchdog);
+ ExtendedMockito.doNothing().when(() -> RescueParty.registerHealthObserver(context));
+ mLifecycle = new Lifecycle(context);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ mSession.finishMocking();
+ }
+
+ @Test
+ public void testLifecycleServiceStart() {
+ mLifecycle.onStart();
+
+ verify(mPackageWatchdog, times(1)).noteBoot();
+ ExtendedMockito.verify(() -> RescueParty.registerHealthObserver(any()),
+ Mockito.times(1));
+ }
+
+ @Test
+ public void testLifecycleServiceOnBootPhase() {
+ doNothing().when(mPackageWatchdog).onPackagesReady();
+
+ mLifecycle.onBootPhase(PHASE_ACTIVITY_MANAGER_READY);
+ verify(mPackageWatchdog, never()).onPackagesReady();
+
+ mLifecycle.onBootPhase(PHASE_THIRD_PARTY_APPS_CAN_START);
+ verify(mPackageWatchdog, times(1)).onPackagesReady();
+ }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/crashrecovery/OWNERS b/services/tests/mockingservicestests/src/com/android/server/crashrecovery/OWNERS
new file mode 100644
index 000000000000..8337fd2453df
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/crashrecovery/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/crashrecovery/OWNERS \ No newline at end of file
diff --git a/services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java
index 00daf415375e..1a398c5f1ec3 100644
--- a/services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java
@@ -16,6 +16,8 @@
package com.android.server.trust;
+import static android.security.Flags.FLAG_SHOULD_TRUST_MANAGER_LISTEN_FOR_PRIMARY_AUTH;
+import static android.security.Flags.shouldTrustManagerListenForPrimaryAuth;
import static android.service.trust.TrustAgentService.FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
@@ -73,6 +75,8 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.os.UserManager;
+import android.platform.test.flag.junit.FlagsParameterization;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.Settings;
import android.security.KeyStoreAuthorization;
import android.service.trust.GrantTrustResult;
@@ -91,6 +95,7 @@ import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.LockPatternUtils.StrongAuthTracker;
import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.StrongAuthFlags;
import com.android.internal.widget.LockSettingsInternal;
+import com.android.internal.widget.LockSettingsStateListener;
import com.android.modules.utils.testing.ExtendedMockitoRule;
import com.android.server.LocalServices;
import com.android.server.SystemService;
@@ -101,6 +106,7 @@ import org.junit.Before;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
+import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatcher;
import org.mockito.Mock;
@@ -112,7 +118,16 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
+import platform.test.runner.parameterized.Parameters;
+
+@RunWith(ParameterizedAndroidJunit4.class)
public class TrustManagerServiceTest {
+ @Parameters(name = "{0}")
+ public static List<FlagsParameterization> getParams() {
+ return FlagsParameterization.allCombinationsOf(
+ FLAG_SHOULD_TRUST_MANAGER_LISTEN_FOR_PRIMARY_AUTH);
+ }
@Rule
public final ExtendedMockitoRule mExtendedMockitoRule = new ExtendedMockitoRule.Builder(this)
@@ -122,6 +137,9 @@ public class TrustManagerServiceTest {
.build();
@Rule
+ public final SetFlagsRule mSetFlagsRule;
+
+ @Rule
public final MockContext mMockContext = new MockContext(
ApplicationProvider.getApplicationContext());
@@ -162,6 +180,10 @@ public class TrustManagerServiceTest {
private ITrustManager mTrustManager;
private ActivityManagerInternal mPreviousActivityManagerInternal;
+ public TrustManagerServiceTest(FlagsParameterization flags) {
+ mSetFlagsRule = new SetFlagsRule(SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT, flags);
+ }
+
@Before
public void setUp() throws Exception {
when(mActivityManager.isUserRunning(TEST_USER_ID)).thenReturn(true);
@@ -594,11 +616,27 @@ public class TrustManagerServiceTest {
}
private void attemptSuccessfulUnlock(int userId) throws RemoteException {
- mTrustManager.reportUnlockAttempt(/* successful= */ true, userId);
+ if (shouldTrustManagerListenForPrimaryAuth()) {
+ ArgumentCaptor<LockSettingsStateListener> captor =
+ ArgumentCaptor.forClass(LockSettingsStateListener.class);
+ verify(mLockSettingsInternal).registerLockSettingsStateListener(captor.capture());
+ LockSettingsStateListener listener = captor.getValue();
+ listener.onAuthenticationSucceeded(userId);
+ } else {
+ mTrustManager.reportUnlockAttempt(/* successful= */ true, userId);
+ }
}
private void attemptFailedUnlock(int userId) throws RemoteException {
- mTrustManager.reportUnlockAttempt(/* successful= */ false, userId);
+ if (shouldTrustManagerListenForPrimaryAuth()) {
+ ArgumentCaptor<LockSettingsStateListener> captor =
+ ArgumentCaptor.forClass(LockSettingsStateListener.class);
+ verify(mLockSettingsInternal).registerLockSettingsStateListener(captor.capture());
+ LockSettingsStateListener listener = captor.getValue();
+ listener.onAuthenticationFailed(userId);
+ } else {
+ mTrustManager.reportUnlockAttempt(/* successful= */ false, userId);
+ }
}
private void grantRenewableTrust(ITrustAgentServiceCallback callback) throws RemoteException {
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/WifiPowerStatsCollectorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/WifiPowerStatsCollectorTest.java
index 362607b91763..b13fc530399b 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/WifiPowerStatsCollectorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/WifiPowerStatsCollectorTest.java
@@ -355,7 +355,7 @@ public class WifiPowerStatsCollectorTest {
assertThat(stats.getNumBytesRx()).isEqualTo(13321);
assertThat(stats.getNumPacketsTx()).isEqualTo(263);
assertThat(stats.getNumBytesTx()).isEqualTo(7234);
- assertThat(stats.getScanTimeMillis()).isEqualTo(2200);
+ assertThat(stats.getScanTimeMillis()).isEqualTo(200);
assertThat(stats.getRxTimeMillis()).isEqualTo(6000);
assertThat(stats.getTxTimeMillis()).isEqualTo(1000);
assertThat(stats.getIdleTimeMillis()).isEqualTo(300);
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityUserStateTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityUserStateTest.java
index ca3055196e6d..62fa95149067 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityUserStateTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityUserStateTest.java
@@ -152,6 +152,7 @@ public class AccessibilityUserStateTest {
@Test
public void onSwitchToAnotherUser_userStateClearedNonDefaultValues() {
+ String componentNameString = COMPONENT_NAME.flattenToString();
mUserState.getBoundServicesLocked().add(mMockConnection);
mUserState.getBindingServicesLocked().add(COMPONENT_NAME);
mUserState.setLastSentClientStateLocked(
@@ -162,10 +163,13 @@ public class AccessibilityUserStateTest {
mUserState.setInteractiveUiTimeoutLocked(30);
mUserState.mEnabledServices.add(COMPONENT_NAME);
mUserState.mTouchExplorationGrantedServices.add(COMPONENT_NAME);
- mUserState.updateShortcutTargetsLocked(Set.of(COMPONENT_NAME.flattenToString()), HARDWARE);
- mUserState.updateShortcutTargetsLocked(Set.of(COMPONENT_NAME.flattenToString()), SOFTWARE);
- mUserState.updateShortcutTargetsLocked(Set.of(COMPONENT_NAME.flattenToString()), GESTURE);
- mUserState.setTargetAssignedToAccessibilityButton(COMPONENT_NAME.flattenToString());
+ mUserState.updateShortcutTargetsLocked(Set.of(componentNameString), HARDWARE);
+ mUserState.updateShortcutTargetsLocked(Set.of(componentNameString), SOFTWARE);
+ mUserState.updateShortcutTargetsLocked(Set.of(componentNameString), GESTURE);
+ mUserState.updateShortcutTargetsLocked(Set.of(componentNameString), QUICK_SETTINGS);
+ mUserState.updateA11yTilesInQsPanelLocked(
+ Set.of(AccessibilityShortcutController.COLOR_INVERSION_TILE_COMPONENT_NAME));
+ mUserState.setTargetAssignedToAccessibilityButton(componentNameString);
mUserState.setTouchExplorationEnabledLocked(true);
mUserState.setMagnificationSingleFingerTripleTapEnabledLocked(true);
mUserState.setMagnificationTwoFingerTripleTapEnabledLocked(true);
@@ -189,6 +193,8 @@ public class AccessibilityUserStateTest {
assertTrue(mUserState.getShortcutTargetsLocked(HARDWARE).isEmpty());
assertTrue(mUserState.getShortcutTargetsLocked(SOFTWARE).isEmpty());
assertTrue(mUserState.getShortcutTargetsLocked(GESTURE).isEmpty());
+ assertTrue(mUserState.getShortcutTargetsLocked(QUICK_SETTINGS).isEmpty());
+ assertTrue(mUserState.getA11yQsTilesInQsPanel().isEmpty());
assertNull(mUserState.getTargetAssignedToAccessibilityButton());
assertFalse(mUserState.isTouchExplorationEnabledLocked());
assertFalse(mUserState.isMagnificationSingleFingerTripleTapEnabledLocked());
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/MouseKeysInterceptorTest.kt b/services/tests/servicestests/src/com/android/server/accessibility/MouseKeysInterceptorTest.kt
index dc8d2390ef2d..0def51691efa 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/MouseKeysInterceptorTest.kt
+++ b/services/tests/servicestests/src/com/android/server/accessibility/MouseKeysInterceptorTest.kt
@@ -16,6 +16,8 @@
package com.android.server.accessibility
+import android.util.MathUtils.sqrt
+
import android.companion.virtual.VirtualDeviceManager
import android.companion.virtual.VirtualDeviceParams
import android.content.Context
@@ -59,6 +61,7 @@ class MouseKeysInterceptorTest {
companion object {
const val DISPLAY_ID = 1
const val DEVICE_ID = 123
+ const val MOUSE_POINTER_MOVEMENT_STEP = 1.8f
// This delay is required for key events to be sent and handled correctly.
// The handler only performs a move/scroll event if it receives the key event
// at INTERVAL_MILLIS (which happens in practice). Hence, we need this delay in the tests.
@@ -113,8 +116,7 @@ class MouseKeysInterceptorTest {
Mockito.`when`(iInputManager.inputDeviceIds).thenReturn(intArrayOf(DEVICE_ID))
Mockito.`when`(mockAms.traceManager).thenReturn(mockTraceManager)
- mouseKeysInterceptor = MouseKeysInterceptor(mockAms, mockInputManager,
- testLooper.looper, DISPLAY_ID)
+ mouseKeysInterceptor = MouseKeysInterceptor(mockAms, testLooper.looper, DISPLAY_ID)
// VirtualMouse is created on a separate thread.
// Wait for VirtualMouse to be created before running tests
TimeUnit.MILLISECONDS.sleep(20L)
@@ -145,7 +147,7 @@ class MouseKeysInterceptorTest {
fun whenMouseDirectionalKeyIsPressed_relativeEventIsSent() {
// There should be some delay between the downTime of the key event and calling onKeyEvent
val downTime = clock.now() - KEYBOARD_POST_EVENT_DELAY_MILLIS
- val keyCode = MouseKeysInterceptor.MouseKeyEvent.DOWN_MOVE.getKeyCodeValue()
+ val keyCode = MouseKeysInterceptor.MouseKeyEvent.DIAGONAL_DOWN_LEFT_MOVE.keyCodeValue
val downEvent = KeyEvent(downTime, downTime, KeyEvent.ACTION_DOWN,
keyCode, 0, 0, DEVICE_ID, 0)
@@ -153,14 +155,15 @@ class MouseKeysInterceptorTest {
testLooper.dispatchAll()
// Verify the sendRelativeEvent method is called once and capture the arguments
- verifyRelativeEvents(arrayOf<Float>(0f), arrayOf<Float>(1.8f))
+ verifyRelativeEvents(arrayOf(-MOUSE_POINTER_MOVEMENT_STEP / sqrt(2.0f)),
+ arrayOf(MOUSE_POINTER_MOVEMENT_STEP / sqrt(2.0f)))
}
@Test
fun whenClickKeyIsPressed_buttonEventIsSent() {
// There should be some delay between the downTime of the key event and calling onKeyEvent
val downTime = clock.now() - KEYBOARD_POST_EVENT_DELAY_MILLIS
- val keyCode = MouseKeysInterceptor.MouseKeyEvent.LEFT_CLICK.getKeyCodeValue()
+ val keyCode = MouseKeysInterceptor.MouseKeyEvent.LEFT_CLICK.keyCodeValue
val downEvent = KeyEvent(downTime, downTime, KeyEvent.ACTION_DOWN,
keyCode, 0, 0, DEVICE_ID, 0)
mouseKeysInterceptor.onKeyEvent(downEvent, 0)
@@ -179,7 +182,7 @@ class MouseKeysInterceptorTest {
@Test
fun whenHoldKeyIsPressed_buttonEventIsSent() {
val downTime = clock.now() - KEYBOARD_POST_EVENT_DELAY_MILLIS
- val keyCode = MouseKeysInterceptor.MouseKeyEvent.HOLD.getKeyCodeValue()
+ val keyCode = MouseKeysInterceptor.MouseKeyEvent.HOLD.keyCodeValue
val downEvent = KeyEvent(downTime, downTime, KeyEvent.ACTION_DOWN,
keyCode, 0, 0, DEVICE_ID, 0)
mouseKeysInterceptor.onKeyEvent(downEvent, 0)
@@ -195,7 +198,7 @@ class MouseKeysInterceptorTest {
@Test
fun whenReleaseKeyIsPressed_buttonEventIsSent() {
val downTime = clock.now() - KEYBOARD_POST_EVENT_DELAY_MILLIS
- val keyCode = MouseKeysInterceptor.MouseKeyEvent.RELEASE.getKeyCodeValue()
+ val keyCode = MouseKeysInterceptor.MouseKeyEvent.RELEASE.keyCodeValue
val downEvent = KeyEvent(downTime, downTime, KeyEvent.ACTION_DOWN,
keyCode, 0, 0, DEVICE_ID, 0)
mouseKeysInterceptor.onKeyEvent(downEvent, 0)
@@ -209,18 +212,38 @@ class MouseKeysInterceptorTest {
}
@Test
- fun whenScrollUpKeyIsPressed_scrollEventIsSent() {
+ fun whenScrollToggleOn_ScrollUpKeyIsPressed_scrollEventIsSent() {
// There should be some delay between the downTime of the key event and calling onKeyEvent
val downTime = clock.now() - KEYBOARD_POST_EVENT_DELAY_MILLIS
- val keyCode = MouseKeysInterceptor.MouseKeyEvent.SCROLL_UP.getKeyCodeValue()
+ val keyCodeScrollToggle = MouseKeysInterceptor.MouseKeyEvent.SCROLL_TOGGLE.keyCodeValue
+ val keyCodeScroll = MouseKeysInterceptor.MouseKeyEvent.UP_MOVE_OR_SCROLL.keyCodeValue
+
+ val scrollToggleDownEvent = KeyEvent(downTime, downTime, KeyEvent.ACTION_DOWN,
+ keyCodeScrollToggle, 0, 0, DEVICE_ID, 0)
+ val scrollDownEvent = KeyEvent(downTime, downTime, KeyEvent.ACTION_DOWN,
+ keyCodeScroll, 0, 0, DEVICE_ID, 0)
+
+ mouseKeysInterceptor.onKeyEvent(scrollToggleDownEvent, 0)
+ mouseKeysInterceptor.onKeyEvent(scrollDownEvent, 0)
+ testLooper.dispatchAll()
+
+ // Verify the sendScrollEvent method is called once and capture the arguments
+ verifyScrollEvents(arrayOf<Float>(0f), arrayOf<Float>(1.0f))
+ }
+
+ @Test
+ fun whenScrollToggleOff_DirectionalUpKeyIsPressed_RelativeEventIsSent() {
+ // There should be some delay between the downTime of the key event and calling onKeyEvent
+ val downTime = clock.now() - KEYBOARD_POST_EVENT_DELAY_MILLIS
+ val keyCode = MouseKeysInterceptor.MouseKeyEvent.UP_MOVE_OR_SCROLL.keyCodeValue
val downEvent = KeyEvent(downTime, downTime, KeyEvent.ACTION_DOWN,
keyCode, 0, 0, DEVICE_ID, 0)
mouseKeysInterceptor.onKeyEvent(downEvent, 0)
testLooper.dispatchAll()
- // Verify the sendScrollEvent method is called once and capture the arguments
- verifyScrollEvents(arrayOf<Float>(0f), arrayOf<Float>(1.0f))
+ // Verify the sendRelativeEvent method is called once and capture the arguments
+ verifyRelativeEvents(arrayOf<Float>(0f), arrayOf<Float>(-MOUSE_POINTER_MOVEMENT_STEP))
}
private fun verifyRelativeEvents(expectedX: Array<Float>, expectedY: Array<Float>) {
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecNetworkTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecNetworkTest.java
index 10f4308cbcfb..599a3b86e1af 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecNetworkTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecNetworkTest.java
@@ -396,7 +396,7 @@ public class HdmiCecNetworkTest {
}
@Test
- public void cecDevices_tracking_updatesPhysicalAddress() {
+ public void cecDevices_tracking_updatesPhysicalAddress_add() {
int logicalAddress = Constants.ADDR_PLAYBACK_1;
int initialPhysicalAddress = 0x1000;
int updatedPhysicalAddress = 0x2000;
@@ -415,11 +415,12 @@ public class HdmiCecNetworkTest {
assertThat(cecDeviceInfo.getPhysicalAddress()).isEqualTo(updatedPhysicalAddress);
assertThat(cecDeviceInfo.getDeviceType()).isEqualTo(type);
- // ADD for physical address first detected
- // UPDATE for updating device with new physical address
+ // Handle case where PA is changed: Update CEC device information by calling
+ // addCecDevice().
assertThat(mDeviceEventListenerStatuses).containsExactly(
HdmiControlManager.DEVICE_EVENT_ADD_DEVICE,
- HdmiControlManager.DEVICE_EVENT_UPDATE_DEVICE);
+ HdmiControlManager.DEVICE_EVENT_REMOVE_DEVICE,
+ HdmiControlManager.DEVICE_EVENT_ADD_DEVICE);
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java
index e64397d4223b..316b5faf2a68 100644
--- a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java
@@ -17,6 +17,7 @@
package com.android.server.media.projection;
+import static android.Manifest.permission.RECORD_SENSITIVE_CONTENT;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
import static android.media.projection.MediaProjectionManager.TYPE_MIRRORING;
@@ -50,6 +51,7 @@ import static org.testng.Assert.assertThrows;
import android.app.ActivityManagerInternal;
import android.app.ActivityOptions.LaunchCookie;
+import android.app.KeyguardManager;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.pm.ApplicationInfo;
@@ -66,7 +68,9 @@ import android.os.Looper;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.test.TestLooper;
+import android.platform.test.annotations.EnableFlags;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.view.ContentRecordingSession;
import android.view.ContentRecordingSession.RecordContent;
@@ -81,6 +85,7 @@ import com.android.server.wm.WindowManagerInternal;
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -151,6 +156,9 @@ public class MediaProjectionManagerServiceTest {
private ContentRecordingSession mWaitingDisplaySession =
createDisplaySession(DEFAULT_DISPLAY);
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
@Mock
private ActivityManagerInternal mAmInternal;
@Mock
@@ -158,6 +166,8 @@ public class MediaProjectionManagerServiceTest {
@Mock
private PackageManager mPackageManager;
@Mock
+ private KeyguardManager mKeyguardManager;
+ @Mock
private IMediaProjectionWatcherCallback mWatcherCallback;
@Mock
private MediaProjectionMetricsLogger mMediaProjectionMetricsLogger;
@@ -177,6 +187,7 @@ public class MediaProjectionManagerServiceTest {
mContext = spy(new ContextWrapper(
InstrumentationRegistry.getInstrumentation().getTargetContext()));
doReturn(mPackageManager).when(mContext).getPackageManager();
+ doReturn(mKeyguardManager).when(mContext).getSystemService(eq(Context.KEYGUARD_SERVICE));
mClock = new OffsettableClock.Stopped();
mWaitingDisplaySession.setWaitingForConsent(true);
@@ -246,6 +257,39 @@ public class MediaProjectionManagerServiceTest {
assertThat(stoppedCallback2).isFalse();
}
+ @EnableFlags(android.companion.virtualdevice.flags
+ .Flags.FLAG_MEDIA_PROJECTION_KEYGUARD_RESTRICTIONS)
+ @Test
+ public void testCreateProjection_keyguardLocked() throws Exception {
+ MediaProjectionManagerService.MediaProjection projection = startProjectionPreconditions();
+
+ doReturn(true).when(mKeyguardManager).isKeyguardLocked();
+ doReturn(PackageManager.PERMISSION_DENIED).when(mPackageManager)
+ .checkPermission(RECORD_SENSITIVE_CONTENT, projection.packageName);
+ projection.start(mIMediaProjectionCallback);
+ projection.notifyVirtualDisplayCreated(10);
+
+ assertThat(mService.getActiveProjectionInfo()).isNull();
+ assertThat(mIMediaProjectionCallback.mLatch.await(5, TimeUnit.SECONDS)).isTrue();
+ }
+
+ @EnableFlags(android.companion.virtualdevice.flags
+ .Flags.FLAG_MEDIA_PROJECTION_KEYGUARD_RESTRICTIONS)
+ @Test
+ public void testCreateProjection_keyguardLocked_packageAllowlisted()
+ throws NameNotFoundException {
+ MediaProjectionManagerService.MediaProjection projection = startProjectionPreconditions();
+
+ doReturn(true).when(mKeyguardManager).isKeyguardLocked();
+ doReturn(PackageManager.PERMISSION_GRANTED).when(mPackageManager)
+ .checkPermission(RECORD_SENSITIVE_CONTENT, projection.packageName);
+ projection.start(mIMediaProjectionCallback);
+ projection.notifyVirtualDisplayCreated(10);
+
+ // The projection was started because it was allowed to capture the keyguard.
+ assertThat(mService.getActiveProjectionInfo()).isNotNull();
+ }
+
@Test
public void testCreateProjection_attemptReuse_noPriorProjectionGrant()
throws NameNotFoundException {
@@ -317,6 +361,48 @@ public class MediaProjectionManagerServiceTest {
assertThat(secondProjection).isNotEqualTo(projection);
}
+ @EnableFlags(android.companion.virtualdevice.flags
+ .Flags.FLAG_MEDIA_PROJECTION_KEYGUARD_RESTRICTIONS)
+ @Test
+ public void testKeyguardLocked_stopsActiveProjection() throws Exception {
+ MediaProjectionManagerService service =
+ new MediaProjectionManagerService(mContext, mMediaProjectionMetricsLoggerInjector);
+ MediaProjectionManagerService.MediaProjection projection =
+ startProjectionPreconditions(service);
+ projection.start(mIMediaProjectionCallback);
+
+ assertThat(service.getActiveProjectionInfo()).isNotNull();
+
+ doReturn(PackageManager.PERMISSION_DENIED).when(mPackageManager)
+ .checkPermission(RECORD_SENSITIVE_CONTENT, projection.packageName);
+ service.onKeyguardLockedStateChanged(true);
+
+ verify(mMediaProjectionMetricsLogger).logStopped(UID, TARGET_UID_UNKNOWN);
+ assertThat(service.getActiveProjectionInfo()).isNull();
+ assertThat(mIMediaProjectionCallback.mLatch.await(5, TimeUnit.SECONDS)).isTrue();
+ }
+
+ @EnableFlags(android.companion.virtualdevice.flags
+ .Flags.FLAG_MEDIA_PROJECTION_KEYGUARD_RESTRICTIONS)
+ @Test
+ public void testKeyguardLocked_packageAllowlisted_doesNotStopActiveProjection()
+ throws NameNotFoundException {
+ MediaProjectionManagerService service =
+ new MediaProjectionManagerService(mContext, mMediaProjectionMetricsLoggerInjector);
+ MediaProjectionManagerService.MediaProjection projection =
+ startProjectionPreconditions(service);
+ projection.start(mIMediaProjectionCallback);
+
+ assertThat(service.getActiveProjectionInfo()).isNotNull();
+
+ doReturn(PackageManager.PERMISSION_GRANTED).when(mPackageManager).checkPermission(
+ RECORD_SENSITIVE_CONTENT, projection.packageName);
+ service.onKeyguardLockedStateChanged(true);
+
+ verifyZeroInteractions(mMediaProjectionMetricsLogger);
+ assertThat(service.getActiveProjectionInfo()).isNotNull();
+ }
+
@Test
public void stop_noActiveProjections_doesNotLog() throws Exception {
MediaProjectionManagerService service =
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index 02d3b59fbf87..d714db99f18f 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -1060,6 +1060,23 @@ public final class UserManagerTest {
assertThrows(SecurityException.class, userProps::getAlwaysVisible);
}
+ /**
+ * Test that UserManager.getUserProperties throws the IllegalArgumentException for unsupported
+ * arguments such as UserHandle.NULL, UserHandle.CURRENT or UserHandle.ALL.
+ **/
+ @MediumTest
+ @Test
+ public void testThrowUserPropertiesForUnsupportedUserHandles() throws Exception {
+ assertThrows(IllegalArgumentException.class, () ->
+ mUserManager.getUserProperties(UserHandle.of(UserHandle.USER_NULL)));
+ assertThrows(IllegalArgumentException.class, () ->
+ mUserManager.getUserProperties(UserHandle.CURRENT));
+ assertThrows(IllegalArgumentException.class, () ->
+ mUserManager.getUserProperties(UserHandle.CURRENT_OR_SELF));
+ assertThrows(IllegalArgumentException.class, () ->
+ mUserManager.getUserProperties(UserHandle.ALL));
+ }
+
// Make sure only max managed profiles can be created
@MediumTest
@Test
@@ -1845,6 +1862,25 @@ public final class UserManagerTest {
assertThat(profilesExcludingHidden).asList().doesNotContain(profile.id);
}
+ /**
+ * Test that UserManager.isQuietModeEnabled return false for unsupported
+ * arguments such as UserHandle.NULL, UserHandle.CURRENT or UserHandle.ALL.
+ **/
+ @MediumTest
+ @Test
+ public void testQuietModeEnabledForUnsupportedUserHandles() throws Exception {
+ assumeManagedUsersSupported();
+ final int mainUserId = mUserManager.getMainUser().getIdentifier();
+ UserInfo userInfo = createProfileForUser("Profile",
+ UserManager.USER_TYPE_PROFILE_MANAGED, mainUserId);
+ mUserManager.requestQuietModeEnabled(true, userInfo.getUserHandle());
+ assertThat(mUserManager.isQuietModeEnabled(userInfo.getUserHandle())).isTrue();
+ assertThat(mUserManager.isQuietModeEnabled(UserHandle.of(UserHandle.USER_NULL))).isFalse();
+ assertThat(mUserManager.isQuietModeEnabled(UserHandle.CURRENT)).isFalse();
+ assertThat(mUserManager.isQuietModeEnabled(UserHandle.CURRENT_OR_SELF)).isFalse();
+ assertThat(mUserManager.isQuietModeEnabled(UserHandle.ALL)).isFalse();
+ }
+
private String generateLongString() {
String partialString = "Test Name Test Name Test Name Test Name Test Name Test Name Test "
+ "Name Test Name Test Name Test Name "; //String of length 100
diff --git a/services/tests/servicestests/src/com/android/server/power/WakefulnessSessionObserverTest.java b/services/tests/servicestests/src/com/android/server/power/WakefulnessSessionObserverTest.java
index 698f094c8796..6b32be0b2dfd 100644
--- a/services/tests/servicestests/src/com/android/server/power/WakefulnessSessionObserverTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/WakefulnessSessionObserverTest.java
@@ -16,9 +16,14 @@
package com.android.server.power;
+import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_BRIGHT;
+import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_DIM;
+import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_OFF;
import static android.os.PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON;
import static android.os.PowerManager.GO_TO_SLEEP_REASON_TIMEOUT;
import static android.os.PowerManager.WAKE_REASON_POWER_BUTTON;
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.DEFAULT_DISPLAY_GROUP;
import static com.android.server.power.ScreenTimeoutOverridePolicy.RELEASE_REASON_UNKNOWN;
import static com.android.server.power.ScreenTimeoutOverridePolicy.RELEASE_REASON_USER_ACTIVITY_TOUCH;
@@ -27,6 +32,10 @@ import static com.android.server.power.WakefulnessSessionObserver.OVERRIDE_OUTCO
import static com.android.server.power.WakefulnessSessionObserver.OVERRIDE_OUTCOME_CANCEL_USER_INTERACTION;
import static com.android.server.power.WakefulnessSessionObserver.OVERRIDE_OUTCOME_TIMEOUT_SUCCESS;
import static com.android.server.power.WakefulnessSessionObserver.OVERRIDE_OUTCOME_TIMEOUT_USER_INITIATED_REVERT;
+import static com.android.server.power.WakefulnessSessionObserver.POLICY_REASON_BRIGHT_INITIATED_REVERT;
+import static com.android.server.power.WakefulnessSessionObserver.POLICY_REASON_BRIGHT_UNDIM;
+import static com.android.server.power.WakefulnessSessionObserver.POLICY_REASON_OFF_POWER_BUTTON;
+import static com.android.server.power.WakefulnessSessionObserver.POLICY_REASON_OFF_TIMEOUT;
import static com.google.common.truth.Truth.assertThat;
@@ -40,18 +49,24 @@ import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.res.Resources;
+import android.hardware.display.DisplayManagerInternal;
+import android.os.Handler;
import android.os.PowerManager;
import android.os.PowerManagerInternal;
import android.os.UserHandle;
import android.provider.Settings;
import android.test.mock.MockContentResolver;
+import android.view.DisplayAddress;
+import android.view.DisplayInfo;
import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
+import com.android.internal.R;
import com.android.internal.util.test.FakeSettingsProvider;
import com.android.server.testutils.OffsettableClock;
+import com.android.server.testutils.TestHandler;
import org.junit.After;
import org.junit.Before;
@@ -65,25 +80,18 @@ import org.mockito.MockitoAnnotations;
public class WakefulnessSessionObserverTest {
private static final int DEFAULT_SCREEN_OFF_TIMEOUT_MS = 30000;
private static final int OVERRIDE_SCREEN_OFF_TIMEOUT_MS = 15000;
+ private static final int DISPLAY_PORT = 0xFF;
+ private static final long DISPLAY_MODEL = 0xEEEEEEEEL;
private WakefulnessSessionObserver mWakefulnessSessionObserver;
private Context mContext;
private OffsettableClock mTestClock;
@Mock
private WakefulnessSessionObserver.WakefulnessSessionFrameworkStatsLogger
mWakefulnessSessionFrameworkStatsLogger;
- private WakefulnessSessionObserver.Injector mInjector =
- new WakefulnessSessionObserver.Injector() {
- @Override
- WakefulnessSessionObserver.WakefulnessSessionFrameworkStatsLogger
- getWakefulnessSessionFrameworkStatsLogger() {
- return mWakefulnessSessionFrameworkStatsLogger;
- }
- @Override
- WakefulnessSessionObserver.Clock getClock() {
- return mTestClock::now;
- }
- };
+ @Mock
+ private DisplayManagerInternal mDisplayManagerInternal;
+ private TestHandler mHandler;
@Before
public void setUp() {
mTestClock = new OffsettableClock.Stopped();
@@ -95,7 +103,7 @@ public class WakefulnessSessionObserverTest {
final Resources res = spy(mContext.getResources());
doReturn(OVERRIDE_SCREEN_OFF_TIMEOUT_MS).when(res).getInteger(
- com.android.internal.R.integer.config_screenTimeoutOverride);
+ R.integer.config_screenTimeoutOverride);
when(mContext.getResources()).thenReturn(res);
FakeSettingsProvider.clearSettingsProvider();
MockContentResolver mockContentResolver = new MockContentResolver();
@@ -104,7 +112,32 @@ public class WakefulnessSessionObserverTest {
Settings.System.putIntForUser(mockContentResolver, Settings.System.SCREEN_OFF_TIMEOUT,
DEFAULT_SCREEN_OFF_TIMEOUT_MS, UserHandle.USER_CURRENT);
- mWakefulnessSessionObserver = new WakefulnessSessionObserver(mContext, mInjector);
+ final DisplayInfo info = new DisplayInfo();
+ info.address = DisplayAddress.fromPortAndModel(DISPLAY_PORT, DISPLAY_MODEL);
+ mHandler = new TestHandler(null);
+ mWakefulnessSessionObserver = new WakefulnessSessionObserver(
+ mContext, new WakefulnessSessionObserver.Injector() {
+ @Override
+ WakefulnessSessionObserver.WakefulnessSessionFrameworkStatsLogger
+ getWakefulnessSessionFrameworkStatsLogger() {
+ return mWakefulnessSessionFrameworkStatsLogger;
+ }
+ @Override
+ WakefulnessSessionObserver.Clock getClock() {
+ return mTestClock::now;
+ }
+ @Override
+ Handler getHandler() {
+ return mHandler;
+ }
+ @Override
+ DisplayManagerInternal getDisplayManagerInternal() {
+ when(mDisplayManagerInternal.getDisplayInfo(DEFAULT_DISPLAY))
+ .thenReturn(info);
+ return mDisplayManagerInternal;
+ }
+ }
+ );
}
@After
@@ -317,6 +350,167 @@ public class WakefulnessSessionObserverTest {
DEFAULT_SCREEN_OFF_TIMEOUT_MS); // default timeout ms
}
+ @Test
+ public void testOnScreenPolicyUpdate_OffByTimeout() {
+ int userActivity = PowerManager.USER_ACTIVITY_EVENT_ATTENTION;
+ long userActivityTimestamp = mTestClock.now();
+ mWakefulnessSessionObserver.notifyUserActivity(
+ userActivityTimestamp, DEFAULT_DISPLAY_GROUP, userActivity);
+ mWakefulnessSessionObserver.onScreenPolicyUpdate(
+ mTestClock.now(), DEFAULT_DISPLAY_GROUP, POLICY_DIM);
+ mWakefulnessSessionObserver.onWakefulnessChangeStarted(
+ DEFAULT_DISPLAY_GROUP, PowerManagerInternal.WAKEFULNESS_AWAKE,
+ WAKE_REASON_POWER_BUTTON, mTestClock.now());
+ int advancedTime = 5;
+ advanceTime(advancedTime);
+ mWakefulnessSessionObserver.onScreenPolicyUpdate(mTestClock.now(), DEFAULT_DISPLAY_GROUP,
+ POLICY_OFF);
+ mWakefulnessSessionObserver.onWakefulnessChangeStarted(
+ DEFAULT_DISPLAY_GROUP, PowerManagerInternal.WAKEFULNESS_ASLEEP,
+ GO_TO_SLEEP_REASON_TIMEOUT, mTestClock.now());
+
+ verify(mWakefulnessSessionFrameworkStatsLogger)
+ .logDimEvent(
+ DISPLAY_PORT, // physical display port id
+ POLICY_REASON_OFF_TIMEOUT, // policy reason
+ userActivity, // last user activity event
+ advancedTime, // last user activity timestamp
+ advancedTime, // dim duration ms
+ DEFAULT_SCREEN_OFF_TIMEOUT_MS); // default Timeout Ms
+ }
+
+ @Test
+ public void testOnScreenPolicyUpdate_NoLogging_NotDefaultDisplayGroup() {
+ int powerGroupId = 1;
+ int userActivity = PowerManager.USER_ACTIVITY_EVENT_ATTENTION;
+ long userActivityTimestamp = mTestClock.now();
+ int advancedTime = 5;
+ mWakefulnessSessionObserver.notifyUserActivity(
+ userActivityTimestamp, powerGroupId, userActivity);
+ mWakefulnessSessionObserver.onScreenPolicyUpdate(
+ mTestClock.now(), powerGroupId, POLICY_DIM);
+ advanceTime(advancedTime);
+ mWakefulnessSessionObserver.onScreenPolicyUpdate(mTestClock.now(), powerGroupId,
+ POLICY_OFF);
+
+ verify(mWakefulnessSessionFrameworkStatsLogger, never())
+ .logDimEvent(
+ DISPLAY_PORT, // physical display port id
+ POLICY_REASON_OFF_TIMEOUT, // policy reason
+ userActivity, // last user activity event
+ advancedTime, // last user activity timestamp
+ advancedTime, // dim duration ms
+ DEFAULT_SCREEN_OFF_TIMEOUT_MS); // default Timeout Ms
+ }
+
+ @Test
+ public void testOnScreenPolicyUpdate_OffByPowerButton() {
+ // ----- initialize start -----
+ mWakefulnessSessionObserver.onWakefulnessChangeStarted(
+ DEFAULT_DISPLAY_GROUP, PowerManagerInternal.WAKEFULNESS_AWAKE,
+ WAKE_REASON_POWER_BUTTON, mTestClock.now());
+
+ int userActivity = PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY;
+ long userActivityTimestamp = mTestClock.now();
+ mWakefulnessSessionObserver.notifyUserActivity(
+ userActivityTimestamp, DEFAULT_DISPLAY_GROUP, userActivity);
+ mWakefulnessSessionObserver.onScreenPolicyUpdate(
+ mTestClock.now(), DEFAULT_DISPLAY_GROUP, POLICY_DIM);
+ // ----- initialize end -----
+
+ int dimDuration = 500;
+ advanceTime(dimDuration);
+ int userActivityDuration = dimDuration;
+ mWakefulnessSessionObserver.notifyUserActivity(
+ mTestClock.now(), DEFAULT_DISPLAY_GROUP, PowerManager.USER_ACTIVITY_EVENT_BUTTON);
+ mWakefulnessSessionObserver.onWakefulnessChangeStarted(
+ DEFAULT_DISPLAY_GROUP, PowerManagerInternal.WAKEFULNESS_ASLEEP,
+ GO_TO_SLEEP_REASON_POWER_BUTTON, mTestClock.now());
+
+ verify(mWakefulnessSessionFrameworkStatsLogger)
+ .logDimEvent(
+ DISPLAY_PORT, // physical display port id
+ POLICY_REASON_OFF_POWER_BUTTON, // policy reason
+ userActivity, // last user activity event
+ userActivityDuration, // last user activity timestamp
+ dimDuration, // dim duration ms
+ DEFAULT_SCREEN_OFF_TIMEOUT_MS); // default Timeout Ms
+ assertThat(mHandler.getPendingMessages()).isEmpty();
+ }
+
+ @Test
+ public void testOnScreenPolicyUpdate_Undim() {
+ // ----- initialize start -----
+ int userActivity = PowerManager.USER_ACTIVITY_EVENT_TOUCH;
+ long userActivityTimestamp = mTestClock.now();
+ mWakefulnessSessionObserver.notifyUserActivity(
+ userActivityTimestamp, DEFAULT_DISPLAY_GROUP, userActivity);
+ mWakefulnessSessionObserver.onScreenPolicyUpdate(
+ mTestClock.now(), DEFAULT_DISPLAY_GROUP, POLICY_DIM);
+ mWakefulnessSessionObserver.mPowerGroups.get(DEFAULT_DISPLAY_GROUP).mIsInteractive = true;
+ // ----- initialize end -----
+
+ int dimDurationMs = 5;
+ advanceTime(dimDurationMs);
+ mWakefulnessSessionObserver.onScreenPolicyUpdate(
+ mTestClock.now(), DEFAULT_DISPLAY_GROUP, POLICY_BRIGHT);
+
+ int expectedLastUserActivityTimeMs = (int) (mTestClock.now() - userActivityTimestamp);
+
+ mHandler.flush();
+ verify(mWakefulnessSessionFrameworkStatsLogger)
+ .logDimEvent(
+ DISPLAY_PORT, // physical display port id
+ POLICY_REASON_BRIGHT_UNDIM, // policy reason
+ userActivity, // last user activity event
+ expectedLastUserActivityTimeMs, // last user activity timestamp
+ dimDurationMs, // dim duration ms
+ DEFAULT_SCREEN_OFF_TIMEOUT_MS); // default Timeout Ms
+ }
+
+ @Test
+ public void testOnScreenPolicyUpdate_BrightInitiatedRevert() {
+ // ----- initialize start -----
+ mWakefulnessSessionObserver.onScreenPolicyUpdate(
+ mTestClock.now(), DEFAULT_DISPLAY_GROUP, POLICY_DIM);
+ int dimDurationMs = 500;
+ advanceTime(dimDurationMs);
+ int userActivity = PowerManager.USER_ACTIVITY_EVENT_BUTTON;
+ long userActivityTimestamp = mTestClock.now();
+ mWakefulnessSessionObserver.notifyUserActivity(
+ userActivityTimestamp, DEFAULT_DISPLAY_GROUP, userActivity);
+ int userActivityTime = 5;
+ advanceTime(userActivityTime);
+ dimDurationMs += userActivityTime;
+ mWakefulnessSessionObserver.onScreenPolicyUpdate(
+ mTestClock.now(), DEFAULT_DISPLAY_GROUP, POLICY_OFF);
+ mWakefulnessSessionObserver.onWakefulnessChangeStarted(
+ DEFAULT_DISPLAY_GROUP, PowerManagerInternal.WAKEFULNESS_ASLEEP,
+ GO_TO_SLEEP_REASON_POWER_BUTTON, mTestClock.now());
+
+ mWakefulnessSessionObserver.mPowerGroups.get(DEFAULT_DISPLAY_GROUP)
+ .mPastDimDurationMs = dimDurationMs;
+ // ----- initialize end -----
+
+ int advancedTime = 5;
+ advanceTime(advancedTime); // shorter than 5000 ms
+ userActivityTime += advancedTime;
+ mWakefulnessSessionObserver.onScreenPolicyUpdate(mTestClock.now(), DEFAULT_DISPLAY_GROUP,
+ POLICY_BRIGHT);
+ mWakefulnessSessionObserver.onWakefulnessChangeStarted(
+ DEFAULT_DISPLAY_GROUP, PowerManagerInternal.WAKEFULNESS_AWAKE,
+ WAKE_REASON_POWER_BUTTON, mTestClock.now());
+
+ verify(mWakefulnessSessionFrameworkStatsLogger)
+ .logDimEvent(
+ DISPLAY_PORT, // physical display port id
+ POLICY_REASON_BRIGHT_INITIATED_REVERT, // policy reason
+ userActivity, // last user activity event
+ userActivityTime, // last user activity timestamp
+ dimDurationMs, // dim duration ms
+ DEFAULT_SCREEN_OFF_TIMEOUT_MS); // default Timeout Ms
+ }
+
private void advanceTime(long timeMs) {
mTestClock.fastForward(timeMs);
}
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 bf478162c46e..1decd36be394 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
@@ -151,7 +151,6 @@ public class HintManagerServiceTest {
private HintManagerService mService;
private ChannelConfig mConfig;
- private ApplicationInfo mApplicationInfo;
private static Answer<Long> fakeCreateWithConfig(Long ptr, Long sessionId) {
return new Answer<Long>() {
@@ -168,12 +167,12 @@ public class HintManagerServiceTest {
mConfig = new ChannelConfig();
mConfig.readFlagBitmask = 1;
mConfig.writeFlagBitmask = 2;
- mApplicationInfo = new ApplicationInfo();
- mApplicationInfo.category = ApplicationInfo.CATEGORY_GAME;
+ ApplicationInfo applicationInfo = new ApplicationInfo();
+ applicationInfo.category = ApplicationInfo.CATEGORY_GAME;
when(mContext.getPackageManager()).thenReturn(mMockPackageManager);
when(mMockPackageManager.getNameForUid(anyInt())).thenReturn(TEST_APP_NAME);
when(mMockPackageManager.getApplicationInfo(eq(TEST_APP_NAME), anyInt()))
- .thenReturn(mApplicationInfo);
+ .thenReturn(applicationInfo);
when(mNativeWrapperMock.halGetHintSessionPreferredRate())
.thenReturn(DEFAULT_HINT_PREFERRED_RATE);
when(mNativeWrapperMock.halCreateHintSession(eq(TGID), eq(UID), eq(SESSION_TIDS_A),
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAttentionHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAttentionHelperTest.java
index 28a5db904bd9..e06d939a34f7 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAttentionHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAttentionHelperTest.java
@@ -223,6 +223,10 @@ public class NotificationAttentionHelperTest extends UiServiceTestCase {
Settings.System.putInt(getContext().getContentResolver(),
Settings.System.NOTIFICATION_LIGHT_PULSE, 1);
+ // Enable notification cooldown independent of device Settings
+ Settings.System.putInt(getContext().getContentResolver(),
+ Settings.System.NOTIFICATION_COOLDOWN_ENABLED, 1);
+
Resources resources = spy(getContext().getResources());
when(resources.getBoolean(R.bool.config_useAttentionLight)).thenReturn(true);
when(resources.getBoolean(
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 5d306e152ad7..c1f5a01a8c47 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -89,7 +89,6 @@ import static android.os.UserManager.USER_TYPE_FULL_SECONDARY;
import static android.os.UserManager.USER_TYPE_PROFILE_CLONE;
import static android.os.UserManager.USER_TYPE_PROFILE_MANAGED;
import static android.os.UserManager.USER_TYPE_PROFILE_PRIVATE;
-import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT;
import static android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
import static android.service.notification.Adjustment.KEY_CONTEXTUAL_ACTIONS;
import static android.service.notification.Adjustment.KEY_IMPORTANCE;
@@ -838,13 +837,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
// Pretend the shortcut exists
List<ShortcutInfo> shortcutInfos = new ArrayList<>();
- ShortcutInfo info = mock(ShortcutInfo.class);
- when(info.getPackage()).thenReturn(mPkg);
- when(info.getId()).thenReturn(VALID_CONVO_SHORTCUT_ID);
- when(info.getUserId()).thenReturn(USER_SYSTEM);
- when(info.isLongLived()).thenReturn(true);
- when(info.isEnabled()).thenReturn(true);
- shortcutInfos.add(info);
+ shortcutInfos.add(createMockConvoShortcut());
when(mLauncherApps.getShortcuts(any(), any())).thenReturn(shortcutInfos);
when(mShortcutServiceInternal.isSharingShortcut(anyInt(), anyString(), anyString(),
anyString(), anyInt(), any())).thenReturn(true);
@@ -11109,8 +11102,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
BUBBLE_PREFERENCE_ALL /* app */,
true /* channel */);
- ArgumentCaptor<LauncherApps.Callback> launcherAppsCallback =
- ArgumentCaptor.forClass(LauncherApps.Callback.class);
+ ArgumentCaptor<LauncherApps.ShortcutChangeCallback> shortcutChangeCallback =
+ ArgumentCaptor.forClass(LauncherApps.ShortcutChangeCallback.class);
// Messaging notification with shortcut info
Notification.BubbleMetadata metadata =
@@ -11131,7 +11124,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
// Verify:
// Make sure we register the callback for shortcut changes
- verify(mLauncherApps, times(1)).registerCallback(launcherAppsCallback.capture(), any());
+ verify(mShortcutServiceInternal, times(1)).addShortcutChangeCallback(
+ shortcutChangeCallback.capture());
// yes allowed, yes messaging w/shortcut, yes bubble
Notification notif = mService.getNotificationRecord(nr.getSbn().getKey()).getNotification();
@@ -11144,14 +11138,17 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
// Test: Remove the shortcut
when(mLauncherApps.getShortcuts(any(), any())).thenReturn(null);
- launcherAppsCallback.getValue().onShortcutsChanged(mPkg, emptyList(),
+ ArrayList<ShortcutInfo> removedShortcuts = new ArrayList<>();
+ removedShortcuts.add(createMockConvoShortcut());
+ shortcutChangeCallback.getValue().onShortcutsRemoved(mPkg, removedShortcuts,
UserHandle.getUserHandleForUid(mUid));
waitForIdle();
// Verify:
// Make sure callback is unregistered
- verify(mLauncherApps, times(1)).unregisterCallback(launcherAppsCallback.getValue());
+ verify(mShortcutServiceInternal, times(1)).removeShortcutChangeCallback(
+ shortcutChangeCallback.getValue());
// We're no longer a bubble
NotificationRecord notif2 = mService.getNotificationRecord(
@@ -11169,8 +11166,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
BUBBLE_PREFERENCE_ALL /* app */,
true /* channel */);
- ArgumentCaptor<LauncherApps.Callback> launcherAppsCallback =
- ArgumentCaptor.forClass(LauncherApps.Callback.class);
+ ArgumentCaptor<LauncherApps.ShortcutChangeCallback> shortcutChangeCallback =
+ ArgumentCaptor.forClass(LauncherApps.ShortcutChangeCallback.class);
// Messaging notification with shortcut info
Notification.BubbleMetadata metadata = new Notification.BubbleMetadata.Builder(
@@ -11204,7 +11201,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
// Verify:
// Make sure we register the callback for shortcut changes
- verify(mLauncherApps, times(1)).registerCallback(launcherAppsCallback.capture(), any());
+ verify(mShortcutServiceInternal, times(1)).addShortcutChangeCallback(
+ shortcutChangeCallback.capture());
// yes allowed, yes messaging w/shortcut, yes bubble
Notification notif = mService.getNotificationRecord(nr.getSbn().getKey()).getNotification();
@@ -11223,7 +11221,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
// Verify:
// Make sure callback is unregistered
- verify(mLauncherApps, times(1)).unregisterCallback(launcherAppsCallback.getValue());
+ verify(mShortcutServiceInternal, times(1)).removeShortcutChangeCallback(
+ shortcutChangeCallback.getValue());
}
@Test
@@ -16263,4 +16262,14 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
assertThat(r.getChannel().getId()).isEqualTo(NEWS_ID);
}
+
+ private ShortcutInfo createMockConvoShortcut() {
+ ShortcutInfo info = mock(ShortcutInfo.class);
+ when(info.getPackage()).thenReturn(mPkg);
+ when(info.getId()).thenReturn(VALID_CONVO_SHORTCUT_ID);
+ when(info.getUserId()).thenReturn(USER_SYSTEM);
+ when(info.isLongLived()).thenReturn(true);
+ when(info.isEnabled()).thenReturn(true);
+ return info;
+ }
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ShortcutHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ShortcutHelperTest.java
index a4fb16dc1adc..f008cb671e78 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ShortcutHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ShortcutHelperTest.java
@@ -22,17 +22,22 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.PendingIntent;
import android.app.Person;
import android.content.pm.LauncherApps;
import android.content.pm.LauncherApps.ShortcutQuery;
import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutQueryWrapper;
import android.content.pm.ShortcutServiceInternal;
+import android.graphics.drawable.Icon;
import android.os.UserHandle;
import android.os.UserManager;
import android.service.notification.StatusBarNotification;
@@ -50,11 +55,9 @@ import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
-import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
@SmallTest
@@ -64,7 +67,6 @@ public class ShortcutHelperTest extends UiServiceTestCase {
private static final String SHORTCUT_ID = "shortcut";
private static final String PKG = "pkg";
- private static final String KEY = "key";
private static final Person PERSON = mock(Person.class);
@Mock
@@ -75,19 +77,11 @@ public class ShortcutHelperTest extends UiServiceTestCase {
UserManager mUserManager;
@Mock
ShortcutServiceInternal mShortcutServiceInternal;
- @Mock
- NotificationRecord mNr;
- @Mock
- Notification mNotif;
- @Mock
- StatusBarNotification mSbn;
- @Mock
- Notification.BubbleMetadata mBubbleMetadata;
- @Mock
- ShortcutInfo mShortcutInfo;
@Captor private ArgumentCaptor<ShortcutQuery> mShortcutQueryCaptor;
+ NotificationRecord mNr;
+
ShortcutHelper mShortcutHelper;
@Before
@@ -96,137 +90,186 @@ public class ShortcutHelperTest extends UiServiceTestCase {
mShortcutHelper = new ShortcutHelper(
mLauncherApps, mShortcutListener, mShortcutServiceInternal, mUserManager);
- when(mSbn.getPackageName()).thenReturn(PKG);
- when(mShortcutInfo.getId()).thenReturn(SHORTCUT_ID);
- when(mNotif.getBubbleMetadata()).thenReturn(mBubbleMetadata);
- when(mBubbleMetadata.getShortcutId()).thenReturn(SHORTCUT_ID);
when(mUserManager.isUserUnlocked(any(UserHandle.class))).thenReturn(true);
- setUpMockNotificationRecord(mNr, KEY);
+ mNr = setUpNotificationRecord(SHORTCUT_ID, PKG, UserHandle.of(UserHandle.USER_SYSTEM));
}
- private void setUpMockNotificationRecord(NotificationRecord mockRecord, String key) {
- when(mockRecord.getKey()).thenReturn(key);
- when(mockRecord.getSbn()).thenReturn(mSbn);
- when(mockRecord.getNotification()).thenReturn(mNotif);
- when(mockRecord.getShortcutInfo()).thenReturn(mShortcutInfo);
+ private NotificationRecord setUpNotificationRecord(String shortcutId,
+ String pkg,
+ UserHandle user) {
+ ShortcutInfo shortcutInfo = mock(ShortcutInfo.class);
+ when(shortcutInfo.getId()).thenReturn(shortcutId);
+ when(shortcutInfo.getUserHandle()).thenReturn(user);
+ when(shortcutInfo.isLongLived()).thenReturn(true);
+
+ Notification notification = new Notification.Builder(getContext())
+ .setContentTitle("title")
+ .setShortcutId(shortcutId)
+ .setBubbleMetadata(new Notification.BubbleMetadata.Builder(shortcutId).build())
+ .build();
+
+ StatusBarNotification sbn = new StatusBarNotification(pkg, pkg, 0, null,
+ 1000, 2000, notification, user, null, System.currentTimeMillis());
+ NotificationRecord record = new NotificationRecord(mContext, sbn,
+ mock(NotificationChannel.class));
+ record.setShortcutInfo(shortcutInfo);
+ return record;
}
- private LauncherApps.Callback addShortcutBubbleAndVerifyListener() {
- mShortcutHelper.maybeListenForShortcutChangesForBubbles(mNr,
- false /* removed */,
- null /* handler */);
+ private LauncherApps.ShortcutChangeCallback addShortcutBubbleAndVerifyListener(
+ NotificationRecord record) {
+ mShortcutHelper.maybeListenForShortcutChangesForBubbles(record, false /* removed */);
- ArgumentCaptor<LauncherApps.Callback> launcherAppsCallback =
- ArgumentCaptor.forClass(LauncherApps.Callback.class);
+ ArgumentCaptor<LauncherApps.ShortcutChangeCallback> launcherAppsCallback =
+ ArgumentCaptor.forClass(LauncherApps.ShortcutChangeCallback.class);
- verify(mLauncherApps, times(1)).registerCallback(
- launcherAppsCallback.capture(), any());
+ verify(mShortcutServiceInternal, times(1)).addShortcutChangeCallback(
+ launcherAppsCallback.capture());
return launcherAppsCallback.getValue();
}
@Test
public void testBubbleAdded_listenedAdded() {
- addShortcutBubbleAndVerifyListener();
+ addShortcutBubbleAndVerifyListener(mNr);
}
@Test
+ public void testListenerNotifiedOnShortcutRemoved() {
+ LauncherApps.ShortcutChangeCallback callback = addShortcutBubbleAndVerifyListener(mNr);
+
+ List<ShortcutInfo> removedShortcuts = new ArrayList<>();
+ removedShortcuts.add(mNr.getShortcutInfo());
+
+ callback.onShortcutsRemoved(PKG, removedShortcuts, mNr.getUser());
+ verify(mShortcutListener).onShortcutRemoved(mNr.getKey());
+ }
+
+ @Test
+ public void testListenerNotNotified_notMatchingPackage() {
+ LauncherApps.ShortcutChangeCallback callback = addShortcutBubbleAndVerifyListener(mNr);
+
+ List<ShortcutInfo> removedShortcuts = new ArrayList<>();
+ removedShortcuts.add(mNr.getShortcutInfo());
+
+ callback.onShortcutsRemoved("differentPackage", removedShortcuts, mNr.getUser());
+ verify(mShortcutListener, never()).onShortcutRemoved(anyString());
+ }
+
+ @Test
+ public void testListenerNotNotified_notMatchingUser() {
+ LauncherApps.ShortcutChangeCallback callback = addShortcutBubbleAndVerifyListener(mNr);
+
+ List<ShortcutInfo> removedShortcuts = new ArrayList<>();
+ removedShortcuts.add(mNr.getShortcutInfo());
+
+ callback.onShortcutsRemoved(PKG, removedShortcuts, UserHandle.of(10));
+ verify(mShortcutListener, never()).onShortcutRemoved(anyString());
+ }
+
+ @Test
+ public void testListenerNotifiedDifferentUser() {
+ LauncherApps.ShortcutChangeCallback callback = addShortcutBubbleAndVerifyListener(mNr);
+ NotificationRecord diffUserRecord = setUpNotificationRecord(SHORTCUT_ID, PKG,
+ UserHandle.of(10));
+ mShortcutHelper.maybeListenForShortcutChangesForBubbles(diffUserRecord,
+ false /* removed */);
+
+ List<ShortcutInfo> removedShortcuts = new ArrayList<>();
+ removedShortcuts.add(mNr.getShortcutInfo());
+
+ callback.onShortcutsRemoved(PKG, removedShortcuts, mNr.getUser());
+ verify(mShortcutListener).onShortcutRemoved(mNr.getKey());
+
+ reset(mShortcutListener);
+ removedShortcuts.clear();
+ removedShortcuts.add(diffUserRecord.getShortcutInfo());
+
+ callback.onShortcutsRemoved(PKG, removedShortcuts, diffUserRecord.getUser());
+ verify(mShortcutListener).onShortcutRemoved(diffUserRecord.getKey());
+ }
+
+
+ @Test
public void testBubbleRemoved_listenerRemoved() {
// First set it up to listen
- addShortcutBubbleAndVerifyListener();
+ addShortcutBubbleAndVerifyListener(mNr);
// Then remove the notif
mShortcutHelper.maybeListenForShortcutChangesForBubbles(mNr,
- true /* removed */,
- null /* handler */);
+ true /* removed */);
- verify(mLauncherApps, times(1)).unregisterCallback(any());
+ verify(mShortcutServiceInternal, times(1)).removeShortcutChangeCallback(any());
}
@Test
public void testBubbleNoLongerHasBubbleMetadata_listenerRemoved() {
// First set it up to listen
- addShortcutBubbleAndVerifyListener();
+ addShortcutBubbleAndVerifyListener(mNr);
// Then make it not a bubble
- when(mNotif.getBubbleMetadata()).thenReturn(null);
+ mNr.getNotification().setBubbleMetadata(null);
mShortcutHelper.maybeListenForShortcutChangesForBubbles(mNr,
- false /* removed */,
- null /* handler */);
+ false /* removed */);
- verify(mLauncherApps, times(1)).unregisterCallback(any());
+ verify(mShortcutServiceInternal, times(1)).removeShortcutChangeCallback(any());
}
@Test
public void testBubbleNoLongerHasShortcutId_listenerRemoved() {
// First set it up to listen
- addShortcutBubbleAndVerifyListener();
+ addShortcutBubbleAndVerifyListener(mNr);
// Clear out shortcutId
- when(mBubbleMetadata.getShortcutId()).thenReturn(null);
+ mNr.getNotification().setBubbleMetadata(new Notification.BubbleMetadata.Builder(
+ mock(PendingIntent.class), mock(Icon.class)).build());
mShortcutHelper.maybeListenForShortcutChangesForBubbles(mNr,
- false /* removed */,
- null /* handler */);
+ false /* removed */);
- verify(mLauncherApps, times(1)).unregisterCallback(any());
+ verify(mShortcutServiceInternal, times(1)).removeShortcutChangeCallback(any());
}
@Test
public void testNotifNoLongerHasShortcut_listenerRemoved() {
// First set it up to listen
- addShortcutBubbleAndVerifyListener();
-
- NotificationRecord validMock1 = Mockito.mock(NotificationRecord.class);
- setUpMockNotificationRecord(validMock1, "KEY1");
-
- NotificationRecord validMock2 = Mockito.mock(NotificationRecord.class);
- setUpMockNotificationRecord(validMock2, "KEY2");
+ addShortcutBubbleAndVerifyListener(mNr);
- NotificationRecord validMock3 = Mockito.mock(NotificationRecord.class);
- setUpMockNotificationRecord(validMock3, "KEY3");
+ NotificationRecord record1 = setUpNotificationRecord(SHORTCUT_ID, PKG,
+ UserHandle.of(UserHandle.USER_SYSTEM));
+ NotificationRecord record2 = setUpNotificationRecord(SHORTCUT_ID, PKG,
+ UserHandle.of(UserHandle.USER_SYSTEM));
+ NotificationRecord record3 = setUpNotificationRecord(SHORTCUT_ID, PKG,
+ UserHandle.of(UserHandle.USER_SYSTEM));
- mShortcutHelper.maybeListenForShortcutChangesForBubbles(validMock1,
- false /* removed */,
- null /* handler */);
+ mShortcutHelper.maybeListenForShortcutChangesForBubbles(record1,
+ false /* removed */);
- mShortcutHelper.maybeListenForShortcutChangesForBubbles(validMock2,
- false /* removed */,
- null /* handler */);
+ mShortcutHelper.maybeListenForShortcutChangesForBubbles(record2,
+ false /* removed */);
- mShortcutHelper.maybeListenForShortcutChangesForBubbles(validMock3,
- false /* removed */,
- null /* handler */);
+ mShortcutHelper.maybeListenForShortcutChangesForBubbles(record3,
+ false /* removed */);
- // Clear out shortcutId of the bubble in the middle, to double check that we don't hit a
+ // Clear out shortcutId of the bubble in the middle, to double-check that we don't hit a
// concurrent modification exception (removing the last bubble would sidestep that check).
- when(validMock2.getShortcutInfo()).thenReturn(null);
- mShortcutHelper.maybeListenForShortcutChangesForBubbles(validMock2,
- false /* removed */,
- null /* handler */);
+ record2.setShortcutInfo(null);
+ mShortcutHelper.maybeListenForShortcutChangesForBubbles(record2,
+ false /* removed */);
- verify(mLauncherApps, times(1)).unregisterCallback(any());
+ verify(mShortcutServiceInternal, times(1)).removeShortcutChangeCallback(any());
}
@Test
public void testOnShortcutsChanged_listenerRemoved() {
// First set it up to listen
- LauncherApps.Callback callback = addShortcutBubbleAndVerifyListener();
+ LauncherApps.ShortcutChangeCallback callback = addShortcutBubbleAndVerifyListener(mNr);
// App shortcuts are removed:
- callback.onShortcutsChanged(PKG, Collections.emptyList(), mock(UserHandle.class));
+ List<ShortcutInfo> removedShortcuts = new ArrayList<>();
+ removedShortcuts.add(mNr.getShortcutInfo());
+ callback.onShortcutsRemoved(PKG, removedShortcuts, mNr.getUser());
- verify(mLauncherApps, times(1)).unregisterCallback(any());
- }
-
- @Test
- public void testListenerNotifiedOnShortcutRemoved() {
- LauncherApps.Callback callback = addShortcutBubbleAndVerifyListener();
-
- List<ShortcutInfo> shortcutInfos = new ArrayList<>();
- when(mLauncherApps.getShortcuts(any(), any())).thenReturn(shortcutInfos);
-
- callback.onShortcutsChanged(PKG, shortcutInfos, mock(UserHandle.class));
- verify(mShortcutListener).onShortcutRemoved(mNr.getKey());
+ verify(mShortcutServiceInternal, times(1)).removeShortcutChangeCallback(any());
}
@Test
@@ -321,7 +364,6 @@ public class ShortcutHelperTest extends UiServiceTestCase {
.isSameInstanceAs(si);
}
-
@Test
public void testGetValidShortcutInfo_isValidButUserLocked() {
ShortcutInfo si = mock(ShortcutInfo.class);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeEventLoggerFake.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeEventLoggerFake.java
index ff1308c4f6db..1c8cb8f90f1e 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeEventLoggerFake.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeEventLoggerFake.java
@@ -137,4 +137,9 @@ public class ZenModeEventLoggerFake extends ZenModeEventLogger {
checkInRange(i);
return mChanges.get(i).getActiveRuleTypes();
}
+
+ public int getChangeOrigin(int i) throws IllegalArgumentException {
+ checkInRange(i);
+ return mChanges.get(i).getChangeOrigin();
+ }
}
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 7bb633e6e1e0..4bbbc2b28dad 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -818,7 +818,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
// 1. Current ringer is normal
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL);
// Set zen to priority-only with all notification sounds muted (so ringer will be muted)
- Policy totalSilence = new Policy(0,0,0);
+ Policy totalSilence = new Policy(0, 0, 0);
mZenModeHelper.setNotificationPolicy(totalSilence, UPDATE_ORIGIN_APP, 1);
mZenModeHelper.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
@@ -873,7 +873,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
// even when ringer is muted (since all ringer sounds cannot bypass DND),
// system stream is still affected by ringer mode
- mZenModeHelper.setNotificationPolicy(new Policy(0,0,0), UPDATE_ORIGIN_APP, 1);
+ mZenModeHelper.setNotificationPolicy(new Policy(0, 0, 0), UPDATE_ORIGIN_APP, 1);
mZenModeHelper.setManualZenMode(ZEN_MODE_IMPORTANT_INTERRUPTIONS, Uri.EMPTY,
UPDATE_ORIGIN_APP, "test", "caller", 1);
ZenModeHelper.RingerModeDelegate ringerModeDelegateRingerNotMuted =
@@ -1065,9 +1065,10 @@ public class ZenModeHelperTest extends UiServiceTestCase {
@Test
public void testParcelConfig() {
mZenModeHelper.setNotificationPolicy(new Policy(PRIORITY_CATEGORY_EVENTS
- | PRIORITY_CATEGORY_MESSAGES | PRIORITY_CATEGORY_REPEAT_CALLERS
- | PRIORITY_CATEGORY_CONVERSATIONS, PRIORITY_SENDERS_STARRED,
- PRIORITY_SENDERS_STARRED, 0, CONVERSATION_SENDERS_ANYONE), UPDATE_ORIGIN_UNKNOWN,
+ | PRIORITY_CATEGORY_MESSAGES | PRIORITY_CATEGORY_REPEAT_CALLERS
+ | PRIORITY_CATEGORY_CONVERSATIONS, PRIORITY_SENDERS_STARRED,
+ PRIORITY_SENDERS_STARRED, 0, CONVERSATION_SENDERS_ANYONE),
+ UPDATE_ORIGIN_UNKNOWN,
1);
mZenModeHelper.setManualZenRuleDeviceEffects(new ZenDeviceEffects.Builder()
.setShouldDimWallpaper(true)
@@ -1085,13 +1086,14 @@ public class ZenModeHelperTest extends UiServiceTestCase {
@Test
public void testWriteXml() throws Exception {
mZenModeHelper.setNotificationPolicy(new Policy(PRIORITY_CATEGORY_EVENTS
- | PRIORITY_CATEGORY_MESSAGES | PRIORITY_CATEGORY_REPEAT_CALLERS
- | PRIORITY_CATEGORY_CONVERSATIONS, PRIORITY_SENDERS_STARRED,
- PRIORITY_SENDERS_STARRED, SUPPRESSED_EFFECT_BADGE, CONVERSATION_SENDERS_ANYONE),
+ | PRIORITY_CATEGORY_MESSAGES | PRIORITY_CATEGORY_REPEAT_CALLERS
+ | PRIORITY_CATEGORY_CONVERSATIONS, PRIORITY_SENDERS_STARRED,
+ PRIORITY_SENDERS_STARRED, SUPPRESSED_EFFECT_BADGE,
+ CONVERSATION_SENDERS_ANYONE),
UPDATE_ORIGIN_UNKNOWN, 1);
mZenModeHelper.setManualZenRuleDeviceEffects(new ZenDeviceEffects.Builder()
- .setShouldDimWallpaper(true)
- .setShouldDisplayGrayscale(true)
+ .setShouldDimWallpaper(true)
+ .setShouldDisplayGrayscale(true)
.build(), UPDATE_ORIGIN_UNKNOWN, "test", 1);
mZenModeHelper.setManualZenMode(ZEN_MODE_IMPORTANT_INTERRUPTIONS, Uri.EMPTY,
UPDATE_ORIGIN_UNKNOWN, "test", "me", 1);
@@ -2210,7 +2212,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
customDefaultRule.name = "Schedule Default Rule";
customDefaultRule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
ScheduleInfo scheduleInfo = new ScheduleInfo();
- scheduleInfo.days = new int[] { Calendar.SUNDAY };
+ scheduleInfo.days = new int[]{Calendar.SUNDAY};
scheduleInfo.startHour = 18;
scheduleInfo.endHour = 19;
customDefaultRule.conditionId = ZenModeConfig.toScheduleConditionId(scheduleInfo);
@@ -3027,7 +3029,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
// 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,
- Flags.modesApi() ? UPDATE_ORIGIN_USER: UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI, "", null,
+ Flags.modesApi() ? UPDATE_ORIGIN_USER : UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI, "", null,
Process.SYSTEM_UID);
// Now turn zen mode off, but via a different package UID -- this should get registered as
@@ -3060,6 +3062,9 @@ public class ZenModeHelperTest extends UiServiceTestCase {
assertTrue(mZenModeEventLogger.getIsUserAction(0));
assertEquals(Process.SYSTEM_UID, mZenModeEventLogger.getPackageUid(0));
checkDndProtoMatchesSetupZenConfig(mZenModeEventLogger.getPolicyProto(0));
+ // change origin should be populated only under modes_ui
+ assertThat(mZenModeEventLogger.getChangeOrigin(0)).isEqualTo(
+ (Flags.modesApi() && Flags.modesUi()) ? UPDATE_ORIGIN_USER : 0);
// and from turning zen mode off:
// - event ID: DND_TURNED_OFF
@@ -3082,6 +3087,8 @@ public class ZenModeHelperTest extends UiServiceTestCase {
} else {
checkDndProtoMatchesSetupZenConfig(mZenModeEventLogger.getPolicyProto(1));
}
+ assertThat(mZenModeEventLogger.getChangeOrigin(1)).isEqualTo(
+ Flags.modesUi() ? UPDATE_ORIGIN_APP : 0);
}
@Test
@@ -3098,17 +3105,21 @@ public class ZenModeHelperTest extends UiServiceTestCase {
null,
NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
String id = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), zenRule,
- UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI, "test", Process.SYSTEM_UID);
+ UPDATE_ORIGIN_APP, "test", CUSTOM_PKG_UID);
// Event 1: Mimic the rule coming on automatically by setting the Condition to STATE_TRUE
+ // Note that pre-modes_ui, this event serves as a test that automatic changes to an app's
+ // that look like they're coming from the system are attributed to the app, but when
+ // modes_ui is true, we opt to trust the provided change origin.
mZenModeHelper.setAutomaticZenRuleState(id,
new Condition(zenRule.getConditionId(), "", STATE_TRUE),
- UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI, Process.SYSTEM_UID);
+ Flags.modesUi() ? UPDATE_ORIGIN_APP : UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI,
+ CUSTOM_PKG_UID);
// Event 2: "User" turns off the automatic rule (sets it to not enabled)
zenRule.setEnabled(false);
mZenModeHelper.updateAutomaticZenRule(id, zenRule,
- Flags.modesApi() ? UPDATE_ORIGIN_USER: UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI, "",
+ Flags.modesApi() ? UPDATE_ORIGIN_USER : UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI, "",
Process.SYSTEM_UID);
AutomaticZenRule systemRule = new AutomaticZenRule("systemRule",
@@ -3118,7 +3129,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
null,
NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
String systemId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), systemRule,
- Flags.modesApi() ? UPDATE_ORIGIN_USER: UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI, "test",
+ Flags.modesApi() ? UPDATE_ORIGIN_USER : UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI, "test",
Process.SYSTEM_UID);
// Event 3: turn on the system rule
@@ -3128,7 +3139,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
// Event 4: "User" deletes the rule
mZenModeHelper.removeAutomaticZenRule(systemId,
- Flags.modesApi() ? UPDATE_ORIGIN_USER: UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI, "",
+ Flags.modesApi() ? UPDATE_ORIGIN_USER : UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI, "",
Process.SYSTEM_UID);
// In total, this represents 4 events
assertEquals(4, mZenModeEventLogger.numLoggedChanges());
@@ -3151,9 +3162,13 @@ public class ZenModeHelperTest extends UiServiceTestCase {
assertFalse(mZenModeEventLogger.getIsUserAction(0));
assertEquals(CUSTOM_PKG_UID, mZenModeEventLogger.getPackageUid(0));
checkDndProtoMatchesDefaultZenConfig(mZenModeEventLogger.getPolicyProto(0));
+ assertThat(mZenModeEventLogger.getChangeOrigin(0)).isEqualTo(
+ Flags.modesUi() ? UPDATE_ORIGIN_APP : 0);
// When the automatic rule is disabled, this should turn off zen mode and also count as a
// user action. We don't care what the consolidated policy is when DND turns off.
+ // When modes_ui is true, this event should look like a user action attributed to the
+ // specific app.
assertEquals(ZenModeEventLogger.ZenStateChangedEvent.DND_TURNED_OFF.getId(),
mZenModeEventLogger.getEventId(1));
assertEquals(ZEN_MODE_IMPORTANT_INTERRUPTIONS, mZenModeEventLogger.getPrevZenMode(1));
@@ -3161,12 +3176,15 @@ public class ZenModeHelperTest extends UiServiceTestCase {
assertEquals(DNDProtoEnums.AUTOMATIC_RULE, mZenModeEventLogger.getChangedRuleType(1));
assertEquals(0, mZenModeEventLogger.getNumRulesActive(1));
assertTrue(mZenModeEventLogger.getIsUserAction(1));
- assertEquals(Process.SYSTEM_UID, mZenModeEventLogger.getPackageUid(1));
+ assertThat(mZenModeEventLogger.getPackageUid(1)).isEqualTo(
+ Flags.modesUi() ? CUSTOM_PKG_UID : Process.SYSTEM_UID);
if (Flags.modesApi()) {
assertThat(mZenModeEventLogger.getPolicyProto(1)).isNull();
} else {
checkDndProtoMatchesSetupZenConfig(mZenModeEventLogger.getPolicyProto(1));
}
+ assertThat(mZenModeEventLogger.getChangeOrigin(1)).isEqualTo(
+ Flags.modesUi() ? UPDATE_ORIGIN_USER : 0);
// When the system rule is enabled, this counts as an automatic action that comes from the
// system and turns on DND
@@ -3176,6 +3194,8 @@ public class ZenModeHelperTest extends UiServiceTestCase {
assertEquals(1, mZenModeEventLogger.getNumRulesActive(2));
assertFalse(mZenModeEventLogger.getIsUserAction(2));
assertEquals(Process.SYSTEM_UID, mZenModeEventLogger.getPackageUid(2));
+ assertThat(mZenModeEventLogger.getChangeOrigin(2)).isEqualTo(
+ Flags.modesUi() ? UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI : 0);
// When the system rule is deleted, we consider this a user action that turns DND off
// (again)
@@ -3185,6 +3205,8 @@ public class ZenModeHelperTest extends UiServiceTestCase {
assertEquals(0, mZenModeEventLogger.getNumRulesActive(3));
assertTrue(mZenModeEventLogger.getIsUserAction(3));
assertEquals(Process.SYSTEM_UID, mZenModeEventLogger.getPackageUid(3));
+ assertThat(mZenModeEventLogger.getChangeOrigin(3)).isEqualTo(
+ Flags.modesUi() ? UPDATE_ORIGIN_USER : 0);
}
@Test
@@ -3238,6 +3260,8 @@ public class ZenModeHelperTest extends UiServiceTestCase {
assertEquals(1, mZenModeEventLogger.getNumRulesActive(0));
assertTrue(mZenModeEventLogger.getIsUserAction(0));
assertEquals(CUSTOM_PKG_UID, mZenModeEventLogger.getPackageUid(0));
+ assertThat(mZenModeEventLogger.getChangeOrigin(0)).isEqualTo(
+ Flags.modesUi() ? UPDATE_ORIGIN_USER : 0);
// Automatic rule turned off automatically by app:
// - event ID: DND_TURNED_OFF
@@ -3249,6 +3273,8 @@ public class ZenModeHelperTest extends UiServiceTestCase {
assertEquals(0, mZenModeEventLogger.getNumRulesActive(1));
assertFalse(mZenModeEventLogger.getIsUserAction(1));
assertEquals(CUSTOM_PKG_UID, mZenModeEventLogger.getPackageUid(1));
+ assertThat(mZenModeEventLogger.getChangeOrigin(1)).isEqualTo(
+ Flags.modesUi() ? UPDATE_ORIGIN_APP : 0);
// Automatic rule turned on automatically by app:
// - event ID: DND_TURNED_ON
@@ -3261,6 +3287,8 @@ public class ZenModeHelperTest extends UiServiceTestCase {
assertEquals(1, mZenModeEventLogger.getNumRulesActive(2));
assertFalse(mZenModeEventLogger.getIsUserAction(2));
assertEquals(CUSTOM_PKG_UID, mZenModeEventLogger.getPackageUid(2));
+ assertThat(mZenModeEventLogger.getChangeOrigin(2)).isEqualTo(
+ Flags.modesUi() ? UPDATE_ORIGIN_APP : 0);
// Automatic rule turned off automatically by the user:
// - event ID: DND_TURNED_ON
@@ -3272,6 +3300,8 @@ public class ZenModeHelperTest extends UiServiceTestCase {
assertEquals(0, mZenModeEventLogger.getNumRulesActive(3));
assertTrue(mZenModeEventLogger.getIsUserAction(3));
assertEquals(CUSTOM_PKG_UID, mZenModeEventLogger.getPackageUid(3));
+ assertThat(mZenModeEventLogger.getChangeOrigin(3)).isEqualTo(
+ Flags.modesUi() ? UPDATE_ORIGIN_USER : 0);
}
@Test
@@ -3335,7 +3365,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
AutomaticZenRule zenRule = new AutomaticZenRule("name",
null,
- new ComponentName(CUSTOM_PKG_NAME, "ScheduleConditionProvider"),
+ new ComponentName("android", "ScheduleConditionProvider"),
ZenModeConfig.toScheduleConditionId(new ScheduleInfo()),
null,
NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
@@ -3345,7 +3375,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
// Rule 2, same as rule 1
AutomaticZenRule zenRule2 = new AutomaticZenRule("name2",
null,
- new ComponentName(CUSTOM_PKG_NAME, "ScheduleConditionProvider"),
+ new ComponentName("android", "ScheduleConditionProvider"),
ZenModeConfig.toScheduleConditionId(new ScheduleInfo()),
null,
NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
@@ -3395,7 +3425,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
assertEquals(ZEN_MODE_IMPORTANT_INTERRUPTIONS, mZenModeEventLogger.getNewZenMode(0));
assertEquals(1, mZenModeEventLogger.getNumRulesActive(0));
assertFalse(mZenModeEventLogger.getIsUserAction(0));
- assertEquals(CUSTOM_PKG_UID, mZenModeEventLogger.getPackageUid(0));
+ assertEquals(Process.SYSTEM_UID, mZenModeEventLogger.getPackageUid(0));
checkDndProtoMatchesDefaultZenConfig(mZenModeEventLogger.getPolicyProto(0));
// Event 2: rule 2 turns on. This should not change anything about the policy, so the only
@@ -3404,7 +3434,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
mZenModeEventLogger.getEventId(1));
assertEquals(2, mZenModeEventLogger.getNumRulesActive(1));
assertFalse(mZenModeEventLogger.getIsUserAction(1));
- assertEquals(CUSTOM_PKG_UID, mZenModeEventLogger.getPackageUid(1));
+ assertEquals(Process.SYSTEM_UID, mZenModeEventLogger.getPackageUid(1));
checkDndProtoMatchesDefaultZenConfig(mZenModeEventLogger.getPolicyProto(1));
// Event 3: rule 3 turns on. This should trigger a policy change, and be classified as such,
@@ -3482,9 +3512,11 @@ public class ZenModeHelperTest extends UiServiceTestCase {
// 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
// re-evaluated to the one associated with CUSTOM_PKG_NAME.
+ // When modes_ui is true: we expect the change origin to be the source of truth.
mZenModeHelper.setAutomaticZenRuleState(id,
new Condition(zenRule.getConditionId(), "", STATE_TRUE),
- UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI, Process.SYSTEM_UID);
+ Flags.modesUi() ? UPDATE_ORIGIN_APP : UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI,
+ Process.SYSTEM_UID);
// Second: turn on rule 2. This is a system-owned rule and the UID should not be modified
// (nor even looked up; the mock PackageManager won't handle "android" as input).
@@ -3493,7 +3525,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI, Process.SYSTEM_UID);
// Disable rule 1. Because this looks like a user action, the UID should not be modified
- // from the system-provided one.
+ // from the system-provided one unless modes_ui is true.
zenRule.setEnabled(false);
mZenModeHelper.updateAutomaticZenRule(id, zenRule,
UPDATE_ORIGIN_USER, "", Process.SYSTEM_UID);
@@ -3504,6 +3536,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
// Change rule 2's condition, but from some other UID. Since it doesn't look like it's from
// the system, we keep the UID info.
+ // Note that this probably shouldn't be able to occur in real scenarios.
mZenModeHelper.setAutomaticZenRuleState(id2,
new Condition(zenRule2.getConditionId(), "", STATE_FALSE),
UPDATE_ORIGIN_APP, 12345);
@@ -3528,11 +3561,13 @@ public class ZenModeHelperTest extends UiServiceTestCase {
assertEquals(Process.SYSTEM_UID, mZenModeEventLogger.getPackageUid(1));
// Third event: disable rule 1. This looks like a user action so UID should be left alone.
+ // When modes_ui is true, we assign log this user action with the app that owns the rule.
assertEquals(ZenModeEventLogger.ZenStateChangedEvent.DND_ACTIVE_RULES_CHANGED.getId(),
mZenModeEventLogger.getEventId(2));
assertEquals(DNDProtoEnums.AUTOMATIC_RULE, mZenModeEventLogger.getChangedRuleType(2));
assertTrue(mZenModeEventLogger.getIsUserAction(2));
- assertEquals(Process.SYSTEM_UID, mZenModeEventLogger.getPackageUid(2));
+ assertThat(mZenModeEventLogger.getPackageUid(2)).isEqualTo(
+ Flags.modesUi() ? CUSTOM_PKG_UID : Process.SYSTEM_UID);
// Fourth event: turns on manual mode. Doesn't change effective policy so this is just a
// change in active rules. Confirm that the package UID is left unchanged.
@@ -6202,7 +6237,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
public void setManualZenRuleDeviceEffects_noPreexistingMode() {
ZenDeviceEffects effects = new ZenDeviceEffects.Builder()
.setShouldDimWallpaper(true)
- .build();
+ .build();
mZenModeHelper.setManualZenRuleDeviceEffects(effects, UPDATE_ORIGIN_USER, "settings", 1000);
assertThat(mZenModeHelper.getConfig().manualRule).isNotNull();
@@ -6339,21 +6374,21 @@ public class ZenModeHelperTest extends UiServiceTestCase {
private static final Correspondence<ZenRule, ZenRule> IGNORE_METADATA =
Correspondence.transforming(zr -> {
- Parcel p = Parcel.obtain();
- try {
- zr.writeToParcel(p, 0);
- p.setDataPosition(0);
- ZenRule copy = new ZenRule(p);
- copy.creationTime = 0;
- copy.userModifiedFields = 0;
- copy.zenPolicyUserModifiedFields = 0;
- copy.zenDeviceEffectsUserModifiedFields = 0;
- return copy;
- } finally {
- p.recycle();
- }
- },
- "Ignoring timestamp and userModifiedFields");
+ Parcel p = Parcel.obtain();
+ try {
+ zr.writeToParcel(p, 0);
+ p.setDataPosition(0);
+ ZenRule copy = new ZenRule(p);
+ copy.creationTime = 0;
+ copy.userModifiedFields = 0;
+ copy.zenPolicyUserModifiedFields = 0;
+ copy.zenDeviceEffectsUserModifiedFields = 0;
+ return copy;
+ } finally {
+ p.recycle();
+ }
+ },
+ "Ignoring timestamp and userModifiedFields");
private ZenRule expectedImplicitRule(String ownerPkg, int zenMode, ZenPolicy policy,
@Nullable Boolean conditionActive) {
diff --git a/services/tests/wmtests/AndroidManifest.xml b/services/tests/wmtests/AndroidManifest.xml
index 777f6189fdea..6e6b70d319ab 100644
--- a/services/tests/wmtests/AndroidManifest.xml
+++ b/services/tests/wmtests/AndroidManifest.xml
@@ -52,6 +52,7 @@
<uses-permission android:name="android.permission.OBSERVE_ROLE_HOLDERS"/>
<uses-permission android:name="android.permission.MANAGE_DEFAULT_APPLICATIONS"/>
<uses-permission android:name="android.permission.DUMP"/>
+ <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
<!-- TODO: Remove largeHeap hack when memory leak is fixed (b/123984854) -->
<application android:debuggable="true"
diff --git a/services/tests/wmtests/res/xml/bookmarks.xml b/services/tests/wmtests/res/xml/bookmarks.xml
new file mode 100644
index 000000000000..88419e9c441b
--- /dev/null
+++ b/services/tests/wmtests/res/xml/bookmarks.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<bookmarks>
+ <bookmark
+ role="android.app.role.BROWSER"
+ shortcut="b" />
+ <bookmark
+ category="android.intent.category.APP_CONTACTS"
+ shortcut="c" />
+ <bookmark
+ category="android.intent.category.APP_EMAIL"
+ shortcut="e" />
+ <bookmark
+ category="android.intent.category.APP_CALENDAR"
+ shortcut="k" />
+ <bookmark
+ category="android.intent.category.APP_MAPS"
+ shortcut="m" />
+ <bookmark
+ category="android.intent.category.APP_MUSIC"
+ shortcut="p" />
+ <bookmark
+ role="android.app.role.SMS"
+ shortcut="s" />
+ <bookmark
+ category="android.intent.category.APP_CALCULATOR"
+ shortcut="u" />
+</bookmarks>
diff --git a/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutManagerTests.java b/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutManagerTests.java
new file mode 100644
index 000000000000..8c375d413950
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutManagerTests.java
@@ -0,0 +1,167 @@
+/*
+ * 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.policy;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.anyObject;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.res.Resources;
+import android.content.res.XmlResourceParser;
+import android.os.Handler;
+import android.os.Looper;
+import android.view.KeyEvent;
+import android.view.KeyboardShortcutGroup;
+import android.view.KeyboardShortcutInfo;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.R;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Collections;
+
+/**
+ * Test class for {@link ModifierShortcutManager}.
+ *
+ * Build/Install/Run:
+ * atest ModifierShortcutManagerTests
+ */
+
+@SmallTest
+public class ModifierShortcutManagerTests {
+ private ModifierShortcutManager mModifierShortcutManager;
+ private Handler mHandler;
+ private Context mContext;
+ private Resources mResources;
+
+ @Before
+ public void setUp() {
+ mHandler = new Handler(Looper.getMainLooper());
+ mContext = spy(getInstrumentation().getTargetContext());
+ mResources = spy(mContext.getResources());
+
+ XmlResourceParser testBookmarks = mResources.getXml(
+ com.android.frameworks.wmtests.R.xml.bookmarks);
+
+ when(mContext.getResources()).thenReturn(mResources);
+ when(mResources.getXml(R.xml.bookmarks)).thenReturn(testBookmarks);
+
+ mModifierShortcutManager = new ModifierShortcutManager(mContext, mHandler);
+ }
+
+ @Test
+ public void test_getApplicationLaunchKeyboardShortcuts() {
+ KeyboardShortcutGroup group =
+ mModifierShortcutManager.getApplicationLaunchKeyboardShortcuts(-1);
+ assertEquals(8, group.getItems().size());
+ }
+
+ @Test
+ public void test_shortcutInfoFromIntent_appIntent() {
+ Intent mockIntent = mock(Intent.class);
+ ActivityInfo mockActivityInfo = mock(ActivityInfo.class);
+ when(mockActivityInfo.loadLabel(anyObject())).thenReturn("label");
+ mockActivityInfo.packageName = "android";
+ when(mockActivityInfo.getIconResource()).thenReturn(R.drawable.sym_def_app_icon);
+ when(mockIntent.resolveActivityInfo(anyObject(), anyInt())).thenReturn(mockActivityInfo);
+
+ KeyboardShortcutInfo info = mModifierShortcutManager.shortcutInfoFromIntent(
+ 'a', mockIntent, true);
+
+ assertEquals("label", info.getLabel().toString());
+ assertEquals('a', info.getBaseCharacter());
+ assertEquals(R.drawable.sym_def_app_icon, info.getIcon().getResId());
+ assertEquals(KeyEvent.META_META_ON | KeyEvent.META_SHIFT_ON, info.getModifiers());
+
+ }
+
+ @Test
+ public void test_shortcutInfoFromIntent_resolverIntent() {
+ Intent mockIntent = mock(Intent.class);
+ Intent mockSelector = mock(Intent.class);
+ ActivityInfo mockActivityInfo = mock(ActivityInfo.class);
+ mockActivityInfo.name = com.android.internal.app.ResolverActivity.class.getName();
+ when(mockIntent.resolveActivityInfo(anyObject(), anyInt())).thenReturn(mockActivityInfo);
+ when(mockIntent.getSelector()).thenReturn(mockSelector);
+ when(mockSelector.getCategories()).thenReturn(
+ Collections.singleton(Intent.CATEGORY_APP_BROWSER));
+
+ KeyboardShortcutInfo info = mModifierShortcutManager.shortcutInfoFromIntent(
+ 'a', mockIntent, false);
+
+ assertEquals(mContext.getString(R.string.keyboard_shortcut_group_applications_browser),
+ info.getLabel().toString());
+ assertEquals('a', info.getBaseCharacter());
+ assertEquals(R.drawable.sym_def_app_icon, info.getIcon().getResId());
+ assertEquals(KeyEvent.META_META_ON, info.getModifiers());
+
+ // validate that an unknown category that we can't present a label to the user for
+ // returns null shortcut info.
+ when(mockSelector.getCategories()).thenReturn(
+ Collections.singleton("not_a_category"));
+ assertEquals(null, mModifierShortcutManager.shortcutInfoFromIntent(
+ 'a', mockIntent, false));
+ }
+
+ @Test
+ public void test_getIntentCategoryLabel() {
+ assertEquals(
+ mContext.getString(R.string.keyboard_shortcut_group_applications_browser),
+ ModifierShortcutManager.getIntentCategoryLabel(
+ mContext, Intent.CATEGORY_APP_BROWSER));
+ assertEquals(
+ mContext.getString(R.string.keyboard_shortcut_group_applications_contacts),
+ ModifierShortcutManager.getIntentCategoryLabel(
+ mContext, Intent.CATEGORY_APP_CONTACTS));
+ assertEquals(
+ mContext.getString(R.string.keyboard_shortcut_group_applications_email),
+ ModifierShortcutManager.getIntentCategoryLabel(
+ mContext, Intent.CATEGORY_APP_EMAIL));
+ assertEquals(
+ mContext.getString(R.string.keyboard_shortcut_group_applications_calendar),
+ ModifierShortcutManager.getIntentCategoryLabel(
+ mContext, Intent.CATEGORY_APP_CALENDAR));
+ assertEquals(
+ mContext.getString(R.string.keyboard_shortcut_group_applications_maps),
+ ModifierShortcutManager.getIntentCategoryLabel(
+ mContext, Intent.CATEGORY_APP_MAPS));
+ assertEquals(
+ mContext.getString(R.string.keyboard_shortcut_group_applications_music),
+ ModifierShortcutManager.getIntentCategoryLabel(
+ mContext, Intent.CATEGORY_APP_MUSIC));
+ assertEquals(
+ mContext.getString(R.string.keyboard_shortcut_group_applications_sms),
+ ModifierShortcutManager.getIntentCategoryLabel(
+ mContext, Intent.CATEGORY_APP_MESSAGING));
+ assertEquals(
+ mContext.getString(R.string.keyboard_shortcut_group_applications_calculator),
+ ModifierShortcutManager.getIntentCategoryLabel(
+ mContext, Intent.CATEGORY_APP_CALCULATOR));
+ assertEquals(null, ModifierShortcutManager.getIntentCategoryLabel(mContext, "foo"));
+ }
+}
diff --git a/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutTests.java b/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutTests.java
index 0ed02dd0f429..59b08a53a530 100644
--- a/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutTests.java
+++ b/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutTests.java
@@ -65,7 +65,8 @@ public class ModifierShortcutTests extends ShortcutKeyTestBase {
private static final SparseArray<String> INTENT_SHORTCUTS = new SparseArray<>();
private static final SparseArray<String> ROLE_SHORTCUTS = new SparseArray<>();
static {
- // These shortcuts should align with those defined in bookmarks.xml
+ // These shortcuts should align with those defined in
+ // services/tests/wmtests/res/xml/bookmarks.xml
INTENT_SHORTCUTS.append(KEYCODE_U, Intent.CATEGORY_APP_CALCULATOR);
INTENT_SHORTCUTS.append(KEYCODE_C, Intent.CATEGORY_APP_CONTACTS);
INTENT_SHORTCUTS.append(KEYCODE_E, Intent.CATEGORY_APP_EMAIL);
diff --git a/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java b/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java
index dff4984adb80..f5c8fb803fd8 100644
--- a/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java
+++ b/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java
@@ -49,6 +49,7 @@ import static java.util.Collections.unmodifiableMap;
import android.content.Context;
import android.content.res.Resources;
+import android.content.res.XmlResourceParser;
import android.platform.test.flag.junit.SetFlagsRule;
import android.util.ArrayMap;
import android.view.InputDevice;
@@ -102,6 +103,9 @@ class ShortcutKeyTestBase {
doReturn(mResources).when(mContext).getResources();
doReturn(mSettingsProviderRule.mockContentResolver(mContext))
.when(mContext).getContentResolver();
+ XmlResourceParser testBookmarks = mResources.getXml(
+ com.android.frameworks.wmtests.R.xml.bookmarks);
+ doReturn(testBookmarks).when(mResources).getXml(com.android.internal.R.xml.bookmarks);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index eb8825c0c08b..b4505fad1b20 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -684,7 +684,8 @@ public class ActivityRecordTests extends WindowTestsBase {
// Asserts fixed orientation request is not ignored, and the orientation is changed.
assertNotEquals(activityCurOrientation, activity.getConfiguration().orientation);
- assertTrue(activity.isLetterboxedForFixedOrientationAndAspectRatio());
+ assertTrue(activity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio());
}
@Test
@@ -717,7 +718,8 @@ public class ActivityRecordTests extends WindowTestsBase {
// Relaunching the app should still respect the orientation request.
assertEquals(ORIENTATION_PORTRAIT, activity.getConfiguration().orientation);
- assertTrue(activity.isLetterboxedForFixedOrientationAndAspectRatio());
+ assertTrue(activity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio());
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppCompatActivityRobot.java b/services/tests/wmtests/src/com/android/server/wm/AppCompatActivityRobot.java
index f79cdc1da451..867f01fd4699 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppCompatActivityRobot.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppCompatActivityRobot.java
@@ -143,8 +143,8 @@ class AppCompatActivityRobot {
}
void setLetterboxedForFixedOrientationAndAspectRatio(boolean enabled) {
- doReturn(enabled).when(mActivityStack.top())
- .isLetterboxedForFixedOrientationAndAspectRatio();
+ doReturn(enabled).when(mActivityStack.top().mAppCompatController
+ .getAppCompatAspectRatioPolicy()).isLetterboxedForFixedOrientationAndAspectRatio();
}
void enableTreatmentForTopActivity(boolean enabled) {
@@ -163,8 +163,8 @@ class AppCompatActivityRobot {
}
void setShouldApplyUserMinAspectRatioOverride(boolean enabled) {
- doReturn(enabled).when(mActivityStack.top()
- .mLetterboxUiController).shouldApplyUserMinAspectRatioOverride();
+ doReturn(enabled).when(mActivityStack.top().mAppCompatController
+ .getAppCompatAspectRatioOverrides()).shouldApplyUserMinAspectRatioOverride();
}
void setShouldCreateCompatDisplayInsets(boolean enabled) {
@@ -172,13 +172,14 @@ class AppCompatActivityRobot {
}
void setShouldApplyUserFullscreenOverride(boolean enabled) {
- doReturn(enabled).when(mActivityStack.top()
- .mLetterboxUiController).shouldApplyUserFullscreenOverride();
+ doReturn(enabled).when(mActivityStack.top().mAppCompatController
+ .getAppCompatAspectRatioOverrides()).shouldApplyUserFullscreenOverride();
}
void setGetUserMinAspectRatioOverrideCode(@PackageManager.UserMinAspectRatio int orientation) {
doReturn(orientation).when(mActivityStack.top()
- .mLetterboxUiController).getUserMinAspectRatioOverrideCode();
+ .mAppCompatController.getAppCompatAspectRatioOverrides())
+ .getUserMinAspectRatioOverrideCode();
}
void setIgnoreOrientationRequest(boolean enabled) {
@@ -401,6 +402,8 @@ class AppCompatActivityRobot {
mActivityStack.push(activity);
spyOn(activity);
spyOn(activity.mAppCompatController.getTransparentPolicy());
+ spyOn(activity.mAppCompatController.getAppCompatAspectRatioOverrides());
+ spyOn(activity.mAppCompatController.getAppCompatAspectRatioPolicy());
spyOn(activity.mLetterboxUiController);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
index 0c1fbf3cb3d7..af4394acce67 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
@@ -25,15 +25,11 @@ import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_CLOSE;
-import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_CLOSE;
import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_OPEN;
import static android.view.WindowManager.TRANSIT_OLD_DREAM_ACTIVITY_CLOSE;
import static android.view.WindowManager.TRANSIT_OLD_DREAM_ACTIVITY_OPEN;
import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_UNOCCLUDE;
import static android.view.WindowManager.TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE;
-import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CHANGE;
-import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CLOSE;
-import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_OPEN;
import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
@@ -41,7 +37,6 @@ import static android.view.WindowManager.TRANSIT_TO_FRONT;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
-import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -51,14 +46,11 @@ import static org.junit.Assert.fail;
import static org.junit.Assume.assumeFalse;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import android.annotation.Nullable;
-import android.graphics.Rect;
-import android.gui.DropInputMode;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
@@ -841,353 +833,6 @@ public class AppTransitionControllerTest extends WindowTestsBase {
}
@Test
- public void testOverrideTaskFragmentAdapter_overrideWithEmbeddedActivity() {
- final Task task = createTask(mDisplayContent);
- final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
- final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
- setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
-
- // Create a TaskFragment with embedded activity.
- final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer);
- final ActivityRecord activity = taskFragment.getTopMostActivity();
- prepareActivityForAppTransition(activity);
- spyOn(mDisplayContent.mAppTransition);
-
- // Prepare and start transition.
- prepareAndTriggerAppTransition(activity, null /* closingActivity */, taskFragment);
- mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
-
- // Animation run by the remote handler.
- assertTrue(remoteAnimationRunner.isAnimationStarted());
- }
-
- @Test
- public void testOverrideTaskFragmentAdapter_noOverrideWithOnlyTaskFragmentFillingTask() {
- final Task task = createTask(mDisplayContent);
- final ActivityRecord closingActivity = createActivityRecord(task);
- final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
- final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
- setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
-
- // Create a TaskFragment with embedded activity.
- final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer);
-
- // Make sure the TaskFragment is not embedded.
- assertFalse(taskFragment.isEmbeddedWithBoundsOverride());
- final ActivityRecord openingActivity = taskFragment.getTopMostActivity();
- prepareActivityForAppTransition(closingActivity);
- prepareActivityForAppTransition(openingActivity);
- final int uid = 12345;
- closingActivity.info.applicationInfo.uid = uid;
- openingActivity.info.applicationInfo.uid = uid;
- task.effectiveUid = uid;
- spyOn(mDisplayContent.mAppTransition);
-
- // Prepare and start transition.
- prepareAndTriggerAppTransition(openingActivity, closingActivity,
- null /* changingTaskFragment */);
- mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
-
- // Animation is not run by the remote handler because the activity is filling the Task.
- assertFalse(remoteAnimationRunner.isAnimationStarted());
- }
-
- @Test
- public void testOverrideTaskFragmentAdapter_overrideWithTaskFragmentNotFillingTask() {
- final Task task = createTask(mDisplayContent);
- final ActivityRecord closingActivity = createActivityRecord(task);
- final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
- final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
- setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
-
- // Create a TaskFragment with embedded activity.
- final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer);
-
- // Make sure the TaskFragment is embedded.
- taskFragment.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
- final Rect embeddedBounds = new Rect(task.getBounds());
- embeddedBounds.right = embeddedBounds.left + embeddedBounds.width() / 2;
- taskFragment.setBounds(embeddedBounds);
- assertTrue(taskFragment.isEmbeddedWithBoundsOverride());
- final ActivityRecord openingActivity = taskFragment.getTopMostActivity();
- prepareActivityForAppTransition(closingActivity);
- prepareActivityForAppTransition(openingActivity);
- final int uid = 12345;
- closingActivity.info.applicationInfo.uid = uid;
- openingActivity.info.applicationInfo.uid = uid;
- task.effectiveUid = uid;
- spyOn(mDisplayContent.mAppTransition);
-
- // Prepare and start transition.
- prepareAndTriggerAppTransition(openingActivity, closingActivity,
- null /* changingTaskFragment */);
- mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
-
- // Animation run by the remote handler.
- assertTrue(remoteAnimationRunner.isAnimationStarted());
- }
-
- @Test
- public void testOverrideTaskFragmentAdapter_overrideWithNonEmbeddedActivity() {
- final Task task = createTask(mDisplayContent);
- final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
- final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
- setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
-
- // Closing non-embedded activity.
- final ActivityRecord closingActivity = createActivityRecord(task);
- prepareActivityForAppTransition(closingActivity);
- // Opening TaskFragment with embedded activity.
- final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer);
- final ActivityRecord openingActivity = taskFragment.getTopMostActivity();
- prepareActivityForAppTransition(openingActivity);
- task.effectiveUid = openingActivity.getUid();
- spyOn(mDisplayContent.mAppTransition);
-
- // Prepare and start transition.
- prepareAndTriggerAppTransition(openingActivity, closingActivity, taskFragment);
- mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
-
- // Animation run by the remote handler.
- assertTrue(remoteAnimationRunner.isAnimationStarted());
- }
-
- @Test
- public void testOverrideTaskFragmentAdapter_overrideEmbeddedActivityWithDiffUid() {
- final Task task = createTask(mDisplayContent);
- final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
- final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
- setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
-
- // Closing TaskFragment with embedded activity.
- final TaskFragment taskFragment1 = createTaskFragmentWithEmbeddedActivity(task, organizer);
- final ActivityRecord closingActivity = taskFragment1.getTopMostActivity();
- prepareActivityForAppTransition(closingActivity);
- closingActivity.info.applicationInfo.uid = 12345;
- // Opening TaskFragment with embedded activity with different UID.
- final TaskFragment taskFragment2 = createTaskFragmentWithEmbeddedActivity(task, organizer);
- final ActivityRecord openingActivity = taskFragment2.getTopMostActivity();
- prepareActivityForAppTransition(openingActivity);
- openingActivity.info.applicationInfo.uid = 54321;
- spyOn(mDisplayContent.mAppTransition);
-
- // Prepare and start transition.
- prepareAndTriggerAppTransition(openingActivity, closingActivity, taskFragment1);
- mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
-
- // Animation run by the remote handler.
- assertTrue(remoteAnimationRunner.isAnimationStarted());
- }
-
- @Test
- public void testOverrideTaskFragmentAdapter_noOverrideWithTwoApps() {
- final Task task = createTask(mDisplayContent);
- final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
- final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
- setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
-
- // Closing activity in Task1.
- final ActivityRecord closingActivity = createActivityRecord(mDisplayContent);
- prepareActivityForAppTransition(closingActivity);
- // Opening TaskFragment with embedded activity in Task2.
- final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer);
- final ActivityRecord openingActivity = taskFragment.getTopMostActivity();
- prepareActivityForAppTransition(openingActivity);
- spyOn(mDisplayContent.mAppTransition);
-
- // Prepare and start transition.
- prepareAndTriggerAppTransition(openingActivity, closingActivity, taskFragment);
- mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
-
- // Animation not run by the remote handler.
- assertFalse(remoteAnimationRunner.isAnimationStarted());
- }
-
- @Test
- public void testOverrideTaskFragmentAdapter_noOverrideNonEmbeddedActivityWithDiffUid() {
- final Task task = createTask(mDisplayContent);
- final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
- final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
- setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
-
- // Closing TaskFragment with embedded activity.
- final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer);
- final ActivityRecord closingActivity = taskFragment.getTopMostActivity();
- prepareActivityForAppTransition(closingActivity);
- closingActivity.info.applicationInfo.uid = 12345;
- task.effectiveUid = closingActivity.getUid();
- // Opening non-embedded activity with different UID.
- final ActivityRecord openingActivity = createActivityRecord(task);
- prepareActivityForAppTransition(openingActivity);
- openingActivity.info.applicationInfo.uid = 54321;
- spyOn(mDisplayContent.mAppTransition);
-
- // Prepare and start transition.
- prepareAndTriggerAppTransition(openingActivity, closingActivity, taskFragment);
- mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
-
- // Animation should not run by the remote handler when there are non-embedded activities of
- // different UID.
- assertFalse(remoteAnimationRunner.isAnimationStarted());
- }
-
- @Test
- public void testOverrideTaskFragmentAdapter_noOverrideWithWallpaper() {
- final Task task = createTask(mDisplayContent);
- final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
- final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
- setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
-
- // Create a TaskFragment with embedded activity.
- final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer);
- final ActivityRecord activity = taskFragment.getTopMostActivity();
- prepareActivityForAppTransition(activity);
- // Set wallpaper as visible.
- final WallpaperWindowToken wallpaperWindowToken = new WallpaperWindowToken(mWm,
- mock(IBinder.class), true, mDisplayContent, true /* ownerCanManageAppTokens */);
- spyOn(mDisplayContent.mWallpaperController);
- doReturn(true).when(mDisplayContent.mWallpaperController).isWallpaperVisible();
- spyOn(mDisplayContent.mAppTransition);
-
- // Prepare and start transition.
- prepareAndTriggerAppTransition(activity, null /* closingActivity */, taskFragment);
- mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
-
- // Animation should not run by the remote handler when there is wallpaper in the transition.
- assertFalse(remoteAnimationRunner.isAnimationStarted());
- }
-
- @Test
- public void testOverrideTaskFragmentAdapter_inputProtectedForUntrustedAnimation() {
- final Task task = createTask(mDisplayContent);
- final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
- final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
- setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
-
- // Create a TaskFragment with embedded activities, one is trusted embedded, and the other
- // one is untrusted embedded.
- final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm)
- .setParentTask(task)
- .createActivityCount(2)
- .setOrganizer(organizer)
- .build();
- final ActivityRecord activity0 = taskFragment.getChildAt(0).asActivityRecord();
- final ActivityRecord activity1 = taskFragment.getChildAt(1).asActivityRecord();
- // Also create a non-embedded activity in the Task.
- final ActivityRecord activity2 = new ActivityBuilder(mAtm).build();
- task.addChild(activity2, POSITION_BOTTOM);
- prepareActivityForAppTransition(activity0);
- prepareActivityForAppTransition(activity1);
- prepareActivityForAppTransition(activity2);
- doReturn(false).when(taskFragment).isAllowedToEmbedActivityInTrustedMode(activity0);
- doReturn(true).when(taskFragment).isAllowedToEmbedActivityInTrustedMode(activity1);
- spyOn(mDisplayContent.mAppTransition);
-
- // Prepare and start transition.
- prepareAndTriggerAppTransition(activity1, null /* closingActivity */, taskFragment);
- mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
-
- // The animation will be animated remotely by client and all activities are input disabled
- // for untrusted animation.
- assertTrue(remoteAnimationRunner.isAnimationStarted());
- verify(activity0).setDropInputForAnimation(true);
- verify(activity1).setDropInputForAnimation(true);
- verify(activity2).setDropInputForAnimation(true);
- verify(activity0).setDropInputMode(DropInputMode.ALL);
- verify(activity1).setDropInputMode(DropInputMode.ALL);
- verify(activity2).setDropInputMode(DropInputMode.ALL);
-
- // Reset input after animation is finished.
- clearInvocations(activity0);
- clearInvocations(activity1);
- clearInvocations(activity2);
- remoteAnimationRunner.finishAnimation();
-
- verify(activity0).setDropInputForAnimation(false);
- verify(activity1).setDropInputForAnimation(false);
- verify(activity2).setDropInputForAnimation(false);
- verify(activity0).setDropInputMode(DropInputMode.OBSCURED);
- verify(activity1).setDropInputMode(DropInputMode.NONE);
- verify(activity2).setDropInputMode(DropInputMode.NONE);
- }
-
- /**
- * Since we don't have any use case to rely on handling input during animation, disable it even
- * if it is trusted embedding so that it could cover some edge-cases when a previously trusted
- * host starts doing something bad.
- */
- @Test
- public void testOverrideTaskFragmentAdapter_inputProtectedForTrustedAnimation() {
- final Task task = createTask(mDisplayContent);
- final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
- final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
- setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
-
- // Create a TaskFragment with only trusted embedded activity
- final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm)
- .setParentTask(task)
- .createActivityCount(1)
- .setOrganizer(organizer)
- .build();
- final ActivityRecord activity = taskFragment.getChildAt(0).asActivityRecord();
- prepareActivityForAppTransition(activity);
- doReturn(true).when(taskFragment).isAllowedToEmbedActivityInTrustedMode(activity);
- spyOn(mDisplayContent.mAppTransition);
-
- // Prepare and start transition.
- prepareAndTriggerAppTransition(activity, null /* closingActivity */, taskFragment);
- mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
-
- // The animation will be animated remotely by client and all activities are input disabled
- // for untrusted animation.
- assertTrue(remoteAnimationRunner.isAnimationStarted());
- verify(activity).setDropInputForAnimation(true);
- verify(activity).setDropInputMode(DropInputMode.ALL);
-
- // Reset input after animation is finished.
- clearInvocations(activity);
- remoteAnimationRunner.finishAnimation();
-
- verify(activity).setDropInputForAnimation(false);
- verify(activity).setDropInputMode(DropInputMode.NONE);
- }
-
- /**
- * We don't need to drop input for fully trusted embedding (system app, and embedding in the
- * same app). This will allow users to do fast tapping.
- */
- @Test
- public void testOverrideTaskFragmentAdapter_noInputProtectedForFullyTrustedAnimation() {
- final Task task = createTask(mDisplayContent);
- final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
- final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
- setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
-
- // Create a TaskFragment with only trusted embedded activity
- final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm)
- .setParentTask(task)
- .createActivityCount(1)
- .setOrganizer(organizer)
- .build();
- final ActivityRecord activity = taskFragment.getChildAt(0).asActivityRecord();
- prepareActivityForAppTransition(activity);
- final int uid = mAtm.mTaskFragmentOrganizerController.getTaskFragmentOrganizerUid(
- getITaskFragmentOrganizer(organizer));
- doReturn(true).when(task).isFullyTrustedEmbedding(uid);
- spyOn(mDisplayContent.mAppTransition);
-
- // Prepare and start transition.
- prepareAndTriggerAppTransition(activity, null /* closingActivity */, taskFragment);
- mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
-
- // The animation will be animated remotely by client, but input should not be dropped for
- // fully trusted.
- assertTrue(remoteAnimationRunner.isAnimationStarted());
- verify(activity, never()).setDropInputForAnimation(true);
- verify(activity, never()).setDropInputMode(DropInputMode.ALL);
- }
-
- @Test
public void testTransitionGoodToGoForTaskFragments() {
final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
final Task task = createTask(mDisplayContent);
@@ -1253,22 +898,6 @@ public class AppTransitionControllerTest extends WindowTestsBase {
verify(mDisplayContent.mAppTransition).goodToGo(anyInt(), any());
}
- /** Registers remote animation for the organizer. */
- private void setupTaskFragmentRemoteAnimation(TaskFragmentOrganizer organizer,
- TestRemoteAnimationRunner remoteAnimationRunner) {
- final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter(
- remoteAnimationRunner, 10, 1);
- final ITaskFragmentOrganizer iOrganizer = getITaskFragmentOrganizer(organizer);
- final RemoteAnimationDefinition definition = new RemoteAnimationDefinition();
- definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_CHANGE, adapter);
- definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_OPEN, adapter);
- definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_CLOSE, adapter);
- definition.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_OPEN, adapter);
- definition.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_CLOSE, adapter);
- registerTaskFragmentOrganizer(iOrganizer);
- mAtm.mTaskFragmentOrganizerController.registerRemoteAnimations(iOrganizer, definition);
- }
-
private static ITaskFragmentOrganizer getITaskFragmentOrganizer(
TaskFragmentOrganizer organizer) {
return ITaskFragmentOrganizer.Stub.asInterface(organizer.getOrganizerToken().asBinder());
diff --git a/services/tests/wmtests/src/com/android/server/wm/BackgroundLaunchProcessControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/BackgroundLaunchProcessControllerTests.java
index a4df03447754..c9c7e92d71cd 100644
--- a/services/tests/wmtests/src/com/android/server/wm/BackgroundLaunchProcessControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/BackgroundLaunchProcessControllerTests.java
@@ -18,9 +18,11 @@ package com.android.server.wm;
import static com.android.server.wm.ActivityTaskManagerService.APP_SWITCH_ALLOW;
import static com.android.server.wm.ActivityTaskManagerService.APP_SWITCH_DISALLOW;
+import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_BOUND_BY_FOREGROUND;
import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_FOREGROUND;
import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_GRACE_PERIOD;
import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_PERMISSION;
+import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_TOKEN;
import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_VISIBLE_WINDOW;
import static com.android.server.wm.BackgroundActivityStartController.BAL_BLOCK;
@@ -30,12 +32,18 @@ import android.app.BackgroundStartPrivileges;
import android.content.Context;
import android.os.Binder;
import android.os.IBinder;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.flag.junit.SetFlagsRule;
import androidx.test.filters.SmallTest;
import com.android.server.wm.BackgroundActivityStartController.BalVerdict;
+import com.android.window.flags.Flags;
+import org.junit.ClassRule;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -44,6 +52,7 @@ import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
+
/**
* Tests for the {@link BackgroundLaunchProcessController} class.
*
@@ -55,6 +64,10 @@ import java.util.Set;
@RunWith(JUnit4.class)
public class BackgroundLaunchProcessControllerTests {
+
+ @ClassRule public static final SetFlagsRule.ClassRule mClassRule = new SetFlagsRule.ClassRule();
+ @Rule public final SetFlagsRule mSetFlagsRule = mClassRule.createSetFlagsRule();
+
Set<IBinder> mActivityStartAllowed = new HashSet<>();
Set<Integer> mHasActiveVisibleWindow = new HashSet<>();
@@ -113,6 +126,25 @@ public class BackgroundLaunchProcessControllerTests {
}
@Test
+ @DisableFlags(Flags.FLAG_BAL_IMPROVED_METRICS)
+ public void testAllowedByTokenNoCallbackOld() {
+ mController = new BackgroundLaunchProcessController(mHasActiveVisibleWindow::contains,
+ null);
+ Binder token = new Binder();
+ mActivityStartAllowed.add(token);
+ mController.addOrUpdateAllowBackgroundStartPrivileges(token,
+ BackgroundStartPrivileges.ALLOW_BAL);
+ BalVerdict balVerdict = mController.areBackgroundActivityStartsAllowed(
+ mPid, mUid, mPackageName,
+ mAppSwitchState, mIsCheckingForFgsStart,
+ mHasActivityInVisibleTask, mHasBackgroundActivityStartPrivileges,
+ mLastStopAppSwitchesTime, mLastActivityLaunchTime,
+ mLastActivityFinishTime);
+ assertThat(balVerdict.getCode()).isEqualTo(BAL_ALLOW_PERMISSION);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_BAL_IMPROVED_METRICS)
public void testAllowedByTokenNoCallback() {
mController = new BackgroundLaunchProcessController(mHasActiveVisibleWindow::contains,
null);
@@ -126,10 +158,27 @@ public class BackgroundLaunchProcessControllerTests {
mHasActivityInVisibleTask, mHasBackgroundActivityStartPrivileges,
mLastStopAppSwitchesTime, mLastActivityLaunchTime,
mLastActivityFinishTime);
+ assertThat(balVerdict.getCode()).isEqualTo(BAL_ALLOW_TOKEN);
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_BAL_IMPROVED_METRICS)
+ public void testAllowedByTokenOld() {
+ Binder token = new Binder();
+ mActivityStartAllowed.add(token);
+ mController.addOrUpdateAllowBackgroundStartPrivileges(token,
+ BackgroundStartPrivileges.ALLOW_BAL);
+ BalVerdict balVerdict = mController.areBackgroundActivityStartsAllowed(
+ mPid, mUid, mPackageName,
+ mAppSwitchState, mIsCheckingForFgsStart,
+ mHasActivityInVisibleTask, mHasBackgroundActivityStartPrivileges,
+ mLastStopAppSwitchesTime, mLastActivityLaunchTime,
+ mLastActivityFinishTime);
assertThat(balVerdict.getCode()).isEqualTo(BAL_ALLOW_PERMISSION);
}
@Test
+ @EnableFlags(Flags.FLAG_BAL_IMPROVED_METRICS)
public void testAllowedByToken() {
Binder token = new Binder();
mActivityStartAllowed.add(token);
@@ -141,11 +190,12 @@ public class BackgroundLaunchProcessControllerTests {
mHasActivityInVisibleTask, mHasBackgroundActivityStartPrivileges,
mLastStopAppSwitchesTime, mLastActivityLaunchTime,
mLastActivityFinishTime);
- assertThat(balVerdict.getCode()).isEqualTo(BAL_ALLOW_PERMISSION);
+ assertThat(balVerdict.getCode()).isEqualTo(BAL_ALLOW_TOKEN);
}
@Test
- public void testBoundByForeground() {
+ @DisableFlags(Flags.FLAG_BAL_IMPROVED_METRICS)
+ public void testBoundByForegroundOld() {
mAppSwitchState = APP_SWITCH_ALLOW;
mController.addBoundClientUid(999, "visible.package", Context.BIND_ALLOW_ACTIVITY_STARTS);
mHasActiveVisibleWindow.add(999);
@@ -159,6 +209,21 @@ public class BackgroundLaunchProcessControllerTests {
}
@Test
+ @EnableFlags(Flags.FLAG_BAL_IMPROVED_METRICS)
+ public void testBoundByForeground() {
+ mAppSwitchState = APP_SWITCH_ALLOW;
+ mController.addBoundClientUid(999, "visible.package", Context.BIND_ALLOW_ACTIVITY_STARTS);
+ mHasActiveVisibleWindow.add(999);
+ BalVerdict balVerdict = mController.areBackgroundActivityStartsAllowed(
+ mPid, mUid, mPackageName,
+ mAppSwitchState, mIsCheckingForFgsStart,
+ mHasActivityInVisibleTask, mHasBackgroundActivityStartPrivileges,
+ mLastStopAppSwitchesTime, mLastActivityLaunchTime,
+ mLastActivityFinishTime);
+ assertThat(balVerdict.getCode()).isEqualTo(BAL_ALLOW_BOUND_BY_FOREGROUND);
+ }
+
+ @Test
public void testForegroundTask() {
mAppSwitchState = APP_SWITCH_ALLOW;
mHasActivityInVisibleTask = true;
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 5739a04972d9..65aaf605bdfe 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -1871,6 +1871,46 @@ public class DisplayContentTests extends WindowTestsBase {
assertFalse(recentsActivity.hasFixedRotationTransform());
}
+ @EnableFlags(com.android.window.flags.Flags.FLAG_RESPECT_NON_TOP_VISIBLE_FIXED_ORIENTATION)
+ @Test
+ public void testRespectNonTopVisibleFixedOrientation() {
+ spyOn(mWm.mLetterboxConfiguration);
+ doReturn(false).when(mWm.mLetterboxConfiguration).isTranslucentLetterboxingEnabled();
+ makeDisplayPortrait(mDisplayContent);
+ final ActivityRecord nonTopVisible = new ActivityBuilder(mAtm)
+ .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT)
+ .setCreateTask(true).build();
+ final ActivityRecord translucentTop = new ActivityBuilder(mAtm)
+ .setScreenOrientation(SCREEN_ORIENTATION_LANDSCAPE)
+ .setTask(nonTopVisible.getTask()).setVisible(false)
+ .setActivityTheme(android.R.style.Theme_Translucent).build();
+ final TestTransitionPlayer player = registerTestTransitionPlayer();
+ mDisplayContent.requestTransitionAndLegacyPrepare(WindowManager.TRANSIT_OPEN, 0);
+ translucentTop.setVisibility(true);
+ mDisplayContent.updateOrientation();
+ assertEquals("Non-top visible activity must be portrait",
+ Configuration.ORIENTATION_PORTRAIT, nonTopVisible.getConfiguration().orientation);
+ assertEquals("Top translucent activity must be landscape",
+ Configuration.ORIENTATION_LANDSCAPE, translucentTop.getConfiguration().orientation);
+
+ player.start();
+ player.finish();
+ assertEquals("Display must be landscape after the transition is finished",
+ Configuration.ORIENTATION_LANDSCAPE,
+ mDisplayContent.getConfiguration().orientation);
+ assertEquals("Non-top visible activity must still be portrait",
+ Configuration.ORIENTATION_PORTRAIT,
+ nonTopVisible.getConfiguration().orientation);
+
+ translucentTop.finishIfPossible("test", false /* oomAdj */);
+ mDisplayContent.updateOrientation();
+ player.start();
+ player.finish();
+ assertEquals("Display must be portrait after closing the translucent activity",
+ Configuration.ORIENTATION_PORTRAIT,
+ mDisplayContent.getConfiguration().orientation);
+ }
+
@Test
public void testSecondaryInternalDisplayRotationFollowsDefaultDisplay() {
// Skip freezing so the unrelated conditions in updateRotationUnchecked won't disturb.
diff --git a/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java
index 83ad7b1b5d92..708d6860abc2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java
@@ -214,7 +214,8 @@ public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase {
final Rect activityBounds = new Rect(mFirstActivity.getBounds());
// DAG is portrait (860x1200), so Task and Activity fill DAG.
- assertThat(mFirstActivity.isLetterboxedForFixedOrientationAndAspectRatio()).isFalse();
+ assertThat(mFirstActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio()).isFalse();
assertThat(mFirstActivity.inSizeCompatMode()).isFalse();
assertThat(taskBounds).isEqualTo(dagBounds);
assertThat(activityBounds).isEqualTo(taskBounds);
@@ -238,7 +239,8 @@ public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase {
new Rect(mFirstActivity.getConfiguration().windowConfiguration.getBounds());
// DAG is landscape (1200x860), no fixed orientation letterbox
- assertThat(mFirstActivity.isLetterboxedForFixedOrientationAndAspectRatio()).isFalse();
+ assertThat(mFirstActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio()).isFalse();
assertThat(mFirstActivity.inSizeCompatMode()).isTrue();
assertThat(newDagBounds.width()).isEqualTo(dagBounds.height());
assertThat(newDagBounds.height()).isEqualTo(dagBounds.width());
@@ -262,11 +264,13 @@ public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase {
mDisplay.onLastFocusedTaskDisplayAreaChanged(mFirstTda);
prepareUnresizable(mFirstActivity, SCREEN_ORIENTATION_NOSENSOR);
- assertThat(mFirstActivity.isLetterboxedForFixedOrientationAndAspectRatio()).isFalse();
+ assertThat(mFirstActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio()).isFalse();
assertThat(mFirstActivity.inSizeCompatMode()).isFalse();
rotateDisplay(mDisplay, ROTATION_90);
- assertThat(mFirstActivity.isLetterboxedForFixedOrientationAndAspectRatio()).isFalse();
+ assertThat(mFirstActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio()).isFalse();
assertThat(mFirstActivity.inSizeCompatMode()).isFalse();
}
@@ -283,7 +287,8 @@ public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase {
// DAG is portrait (860x1200), and activity is letterboxed for fixed orientation
// (860x[860x860/1200=616]). Task fills DAG.
- assertThat(mFirstActivity.isLetterboxedForFixedOrientationAndAspectRatio()).isTrue();
+ assertThat(mFirstActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio()).isTrue();
assertThat(mFirstActivity.inSizeCompatMode()).isFalse();
assertThat(taskBounds).isEqualTo(dagBounds);
assertThat(activityBounds.width()).isEqualTo(dagBounds.width());
@@ -300,7 +305,8 @@ public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase {
mDisplay.onLastFocusedTaskDisplayAreaChanged(mFirstTda);
prepareUnresizable(mFirstActivity, SCREEN_ORIENTATION_NOSENSOR);
- assertThat(mFirstActivity.isLetterboxedForFixedOrientationAndAspectRatio()).isFalse();
+ assertThat(mFirstActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio()).isFalse();
}
@Test
@@ -310,7 +316,8 @@ public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase {
mDisplay.onLastFocusedTaskDisplayAreaChanged(mFirstTda);
prepareUnresizable(mFirstActivity, SCREEN_ORIENTATION_LOCKED);
- assertThat(mFirstActivity.isLetterboxedForFixedOrientationAndAspectRatio()).isFalse();
+ assertThat(mFirstActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio()).isFalse();
}
@Test
@@ -329,7 +336,8 @@ public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase {
final Rect newActivityBounds = new Rect(mFirstActivity.getBounds());
// DAG is landscape (1200x860), no fixed orientation letterbox
- assertThat(mFirstActivity.isLetterboxedForFixedOrientationAndAspectRatio()).isFalse();
+ assertThat(mFirstActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio()).isFalse();
assertThat(mFirstActivity.inSizeCompatMode()).isTrue();
assertThat(newDagBounds.width()).isEqualTo(dagBounds.height());
assertThat(newDagBounds.height()).isEqualTo(dagBounds.width());
@@ -354,7 +362,8 @@ public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase {
rotateDisplay(mDisplay, ROTATION_90);
- assertThat(mFirstActivity.isLetterboxedForFixedOrientationAndAspectRatio()).isFalse();
+ assertThat(mFirstActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio()).isFalse();
assertThat(mFirstActivity.inSizeCompatMode()).isFalse();
}
@@ -522,7 +531,8 @@ public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase {
assertThat(mDisplay.getLastOrientation()).isEqualTo(SCREEN_ORIENTATION_LANDSCAPE);
assertThat(mFirstRoot.getConfiguration().orientation).isEqualTo(ORIENTATION_PORTRAIT);
assertThat(mFirstActivity.getConfiguration().orientation).isEqualTo(ORIENTATION_PORTRAIT);
- assertThat(mFirstActivity.isLetterboxedForFixedOrientationAndAspectRatio()).isFalse();
+ assertThat(mFirstActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio()).isFalse();
assertThat(mFirstActivity.inSizeCompatMode()).isFalse();
// Launch portrait on second DAG
@@ -534,13 +544,15 @@ public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase {
assertThat(mDisplay.getLastOrientation()).isEqualTo(SCREEN_ORIENTATION_PORTRAIT);
assertThat(mSecondRoot.getConfiguration().orientation).isEqualTo(ORIENTATION_LANDSCAPE);
assertThat(mSecondActivity.getConfiguration().orientation).isEqualTo(ORIENTATION_LANDSCAPE);
- assertThat(mSecondActivity.isLetterboxedForFixedOrientationAndAspectRatio()).isFalse();
+ assertThat(mSecondActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio()).isFalse();
assertThat(mSecondActivity.inSizeCompatMode()).isFalse();
// First activity is letterboxed in portrait as requested.
assertThat(mFirstRoot.getConfiguration().orientation).isEqualTo(ORIENTATION_LANDSCAPE);
assertThat(mFirstActivity.getConfiguration().orientation).isEqualTo(ORIENTATION_PORTRAIT);
- assertThat(mFirstActivity.isLetterboxedForFixedOrientationAndAspectRatio()).isTrue();
+ assertThat(mFirstActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio()).isTrue();
assertThat(mFirstActivity.inSizeCompatMode()).isFalse();
}
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 51b3c4850938..c42367e8ae18 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
@@ -293,6 +293,7 @@ public class LetterboxUiControllerTest extends WindowTestsBase {
mainWindow.mInvGlobalScale = 1f;
spyOn(resources);
spyOn(mActivity);
+ spyOn(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy());
if (taskbar != null) {
taskbar.setVisible(true);
@@ -301,7 +302,8 @@ public class LetterboxUiControllerTest extends WindowTestsBase {
doReturn(mLetterboxedPortraitTaskBounds).when(mActivity).getBounds();
doReturn(false).when(mActivity).isInLetterboxAnimation();
doReturn(true).when(mActivity).isVisible();
- doReturn(true).when(mActivity).isLetterboxedForFixedOrientationAndAspectRatio();
+ doReturn(true).when(mActivity.mAppCompatController
+ .getAppCompatAspectRatioPolicy()).isLetterboxedForFixedOrientationAndAspectRatio();
doReturn(insets).when(mainWindow).getInsetsState();
doReturn(attrs).when(mainWindow).getAttrs();
doReturn(true).when(mainWindow).isDrawn();
@@ -324,10 +326,11 @@ public class LetterboxUiControllerTest extends WindowTestsBase {
mockThatProperty(PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_FULLSCREEN_OVERRIDE,
/* value */ true);
- mController = new LetterboxUiController(mWm, mActivity);
doReturn(false).when(mLetterboxConfiguration).isUserAppAspectRatioFullscreenEnabled();
+ mActivity = setUpActivityWithComponent();
- assertFalse(mController.shouldApplyUserFullscreenOverride());
+ assertFalse(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides()
+ .shouldApplyUserFullscreenOverride());
}
@Test
@@ -337,9 +340,10 @@ public class LetterboxUiControllerTest extends WindowTestsBase {
mockThatProperty(PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_FULLSCREEN_OVERRIDE,
/* value */ false);
- mController = new LetterboxUiController(mWm, mActivity);
+ mActivity = setUpActivityWithComponent();
- assertFalse(mController.shouldApplyUserFullscreenOverride());
+ assertFalse(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides()
+ .shouldApplyUserFullscreenOverride());
}
@Test
@@ -348,16 +352,18 @@ public class LetterboxUiControllerTest extends WindowTestsBase {
prepareActivityThatShouldApplyUserFullscreenOverride();
mockThatProperty(PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_OVERRIDE, /* value */ false);
- mController = new LetterboxUiController(mWm, mActivity);
+ mActivity = setUpActivityWithComponent();
- assertFalse(mController.shouldApplyUserFullscreenOverride());
+ assertFalse(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides()
+ .shouldApplyUserFullscreenOverride());
}
@Test
public void testShouldApplyUserFullscreenOverride_returnsTrue() {
prepareActivityThatShouldApplyUserFullscreenOverride();
- assertTrue(mController.shouldApplyUserFullscreenOverride());
+ assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides()
+ .shouldApplyUserFullscreenOverride());
}
@Test
@@ -369,18 +375,22 @@ public class LetterboxUiControllerTest extends WindowTestsBase {
mActivity = setUpActivityWithComponent();
mController = new LetterboxUiController(mWm, mActivity);
- assertFalse(mController.shouldEnableUserAspectRatioSettings());
+ assertFalse(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides()
+ .shouldEnableUserAspectRatioSettings());
}
@Test
public void testShouldEnableUserAspectRatioSettings_trueProperty_returnsTrue()
throws Exception {
- prepareActivityThatShouldApplyUserMinAspectRatioOverride();
+
mockThatProperty(PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_OVERRIDE, /* value */ true);
+ mActivity = setUpActivityWithComponent();
+ prepareActivityThatShouldApplyUserMinAspectRatioOverride();
mController = new LetterboxUiController(mWm, mActivity);
- assertTrue(mController.shouldEnableUserAspectRatioSettings());
+ assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides()
+ .shouldEnableUserAspectRatioSettings());
}
@Test
@@ -391,7 +401,8 @@ public class LetterboxUiControllerTest extends WindowTestsBase {
mController = new LetterboxUiController(mWm, mActivity);
- assertFalse(mController.shouldEnableUserAspectRatioSettings());
+ assertFalse(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides()
+ .shouldEnableUserAspectRatioSettings());
}
@Test
@@ -400,9 +411,10 @@ public class LetterboxUiControllerTest extends WindowTestsBase {
prepareActivityThatShouldApplyUserMinAspectRatioOverride();
mockThatProperty(PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_OVERRIDE, /* value */ false);
- mController = new LetterboxUiController(mWm, mActivity);
+ mActivity = setUpActivityWithComponent();
- assertFalse(mController.shouldApplyUserMinAspectRatioOverride());
+ assertFalse(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides()
+ .shouldEnableUserAspectRatioSettings());
}
@Test
@@ -411,9 +423,10 @@ public class LetterboxUiControllerTest extends WindowTestsBase {
doReturn(false).when(mLetterboxConfiguration).isUserAppAspectRatioSettingsEnabled();
mockThatProperty(PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_OVERRIDE, /* value */ true);
- mController = new LetterboxUiController(mWm, mActivity);
+ mActivity = setUpActivityWithComponent();
- assertFalse(mController.shouldApplyUserMinAspectRatioOverride());
+ assertFalse(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides()
+ .shouldApplyUserMinAspectRatioOverride());
}
@Test
@@ -421,30 +434,35 @@ public class LetterboxUiControllerTest extends WindowTestsBase {
prepareActivityThatShouldApplyUserMinAspectRatioOverride();
mDisplayContent.setIgnoreOrientationRequest(false);
- assertFalse(mController.shouldApplyUserMinAspectRatioOverride());
+ assertFalse(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides()
+ .shouldApplyUserMinAspectRatioOverride());
}
@Test
public void testShouldApplyUserMinAspectRatioOverride_returnsTrue() {
prepareActivityThatShouldApplyUserMinAspectRatioOverride();
- assertTrue(mController.shouldApplyUserMinAspectRatioOverride());
+ assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides()
+ .shouldApplyUserMinAspectRatioOverride());
}
@Test
public void testShouldApplyUserMinAspectRatioOverride_noIgnoreOrientation_returnsFalse() {
prepareActivityForShouldApplyUserMinAspectRatioOverride(/* orientationRequest */ false);
- assertFalse(mController.shouldApplyUserMinAspectRatioOverride());
+ assertFalse(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides()
+ .shouldApplyUserMinAspectRatioOverride());
}
private void prepareActivityForShouldApplyUserMinAspectRatioOverride(
boolean orientationRequest) {
- spyOn(mController);
+ spyOn(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides());
doReturn(orientationRequest).when(
mLetterboxConfiguration).isUserAppAspectRatioSettingsEnabled();
mDisplayContent.setIgnoreOrientationRequest(true);
- doReturn(USER_MIN_ASPECT_RATIO_3_2).when(mController).getUserMinAspectRatioOverrideCode();
+ doReturn(USER_MIN_ASPECT_RATIO_3_2)
+ .when(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides())
+ .getUserMinAspectRatioOverrideCode();
}
private void prepareActivityThatShouldApplyUserMinAspectRatioOverride() {
@@ -452,10 +470,11 @@ public class LetterboxUiControllerTest extends WindowTestsBase {
}
private void prepareActivityThatShouldApplyUserFullscreenOverride() {
- spyOn(mController);
+ spyOn(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides());
doReturn(true).when(mLetterboxConfiguration).isUserAppAspectRatioFullscreenEnabled();
mDisplayContent.setIgnoreOrientationRequest(true);
- doReturn(USER_MIN_ASPECT_RATIO_FULLSCREEN).when(mController)
+ doReturn(USER_MIN_ASPECT_RATIO_FULLSCREEN)
+ .when(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides())
.getUserMinAspectRatioOverrideCode();
}
@@ -578,9 +597,10 @@ public class LetterboxUiControllerTest extends WindowTestsBase {
@Test
@EnableCompatChanges({OVERRIDE_MIN_ASPECT_RATIO})
public void testshouldOverrideMinAspectRatio_overrideEnabled_returnsTrue() {
- mController = new LetterboxUiController(mWm, mActivity);
+ mActivity = setUpActivityWithComponent();
- assertTrue(mController.shouldOverrideMinAspectRatio());
+ assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides()
+ .shouldOverrideMinAspectRatio());
}
@Test
@@ -588,9 +608,10 @@ public class LetterboxUiControllerTest extends WindowTestsBase {
public void testshouldOverrideMinAspectRatio_propertyTrue_overrideEnabled_returnsTrue()
throws Exception {
mockThatProperty(PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE, /* value */ true);
- mController = new LetterboxUiController(mWm, mActivity);
+ mActivity = setUpActivityWithComponent();
- assertTrue(mController.shouldOverrideMinAspectRatio());
+ assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides()
+ .shouldOverrideMinAspectRatio());
}
@Test
@@ -598,17 +619,19 @@ public class LetterboxUiControllerTest extends WindowTestsBase {
public void testshouldOverrideMinAspectRatio_propertyTrue_overrideDisabled_returnsFalse()
throws Exception {
mockThatProperty(PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE, /* value */ true);
- mController = new LetterboxUiController(mWm, mActivity);
+ mActivity = setUpActivityWithComponent();
- assertFalse(mController.shouldOverrideMinAspectRatio());
+ assertFalse(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides()
+ .shouldOverrideMinAspectRatio());
}
@Test
@DisableCompatChanges({OVERRIDE_MIN_ASPECT_RATIO})
public void testshouldOverrideMinAspectRatio_overrideDisabled_returnsFalse() {
- mController = new LetterboxUiController(mWm, mActivity);
+ mActivity = setUpActivityWithComponent();
- assertFalse(mController.shouldOverrideMinAspectRatio());
+ assertFalse(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides()
+ .shouldOverrideMinAspectRatio());
}
@Test
@@ -618,9 +641,9 @@ public class LetterboxUiControllerTest extends WindowTestsBase {
mockThatProperty(PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE, /* value */ false);
mActivity = setUpActivityWithComponent();
- mController = new LetterboxUiController(mWm, mActivity);
- assertFalse(mController.shouldOverrideMinAspectRatio());
+ assertFalse(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides()
+ .shouldOverrideMinAspectRatio());
}
@Test
@@ -628,9 +651,10 @@ public class LetterboxUiControllerTest extends WindowTestsBase {
public void testshouldOverrideMinAspectRatio_propertyFalse_noOverride_returnsFalse()
throws Exception {
mockThatProperty(PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE, /* value */ false);
- mController = new LetterboxUiController(mWm, mActivity);
+ mActivity = setUpActivityWithComponent();
- assertFalse(mController.shouldOverrideMinAspectRatio());
+ assertFalse(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides()
+ .shouldOverrideMinAspectRatio());
}
@Test
@@ -860,8 +884,10 @@ public class LetterboxUiControllerTest extends WindowTestsBase {
doReturn(true).when(mDisplayContent.mAppCompatCameraPolicy)
.isTreatmentEnabledForActivity(eq(mActivity));
- assertEquals(mController.getSplitScreenAspectRatio(),
- mController.getFixedOrientationLetterboxAspectRatio(
+ final AppCompatAspectRatioOverrides aspectRatioOverrides =
+ mActivity.mAppCompatController.getAppCompatAspectRatioOverrides();
+ assertEquals(aspectRatioOverrides.getSplitScreenAspectRatio(),
+ aspectRatioOverrides.getFixedOrientationLetterboxAspectRatio(
mActivity.getParent().getConfiguration()), /* delta */ 0.01);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
index 3078df026d8a..d29505f02fe8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
@@ -274,17 +274,28 @@ public class RootWindowContainerTests extends WindowTestsBase {
@Test
public void testAttachApplication() {
- final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build();
+ final ActivityRecord activity = new ActivityBuilder(mAtm).setProcessName("testAttach")
+ .setCreateTask(true).build();
+ final ActivityRecord topActivity = new ActivityBuilder(mAtm).setProcessName("testAttach")
+ .setUseProcess(activity.app).setTask(activity.getTask()).build();
activity.detachFromProcess();
- mAtm.startProcessAsync(activity, false /* knownToBeDead */,
+ topActivity.detachFromProcess();
+ mAtm.startProcessAsync(topActivity, false /* knownToBeDead */,
true /* isTop */, "test" /* hostingType */);
+ // Even if the activity is added after topActivity, the start order should still follow
+ // z-order, i.e. the topActivity will be started first.
+ mAtm.startProcessAsync(activity, false /* knownToBeDead */,
+ false /* isTop */, "test" /* hostingType */);
+ assertEquals(2, mAtm.mStartingProcessActivities.size());
+ assertEquals("Top record must be at the tail to start first",
+ topActivity, mAtm.mStartingProcessActivities.get(1));
final WindowProcessController proc = mSystemServicesTestRule.addProcess(
activity.packageName, activity.processName,
6789 /* pid */, activity.info.applicationInfo.uid);
try {
mRootWindowContainer.attachApplication(proc);
- verify(mSupervisor).realStartActivityLocked(eq(activity), eq(proc), anyBoolean(),
- anyBoolean());
+ verify(mSupervisor).realStartActivityLocked(eq(topActivity), eq(proc),
+ anyBoolean(), anyBoolean());
} catch (RemoteException e) {
e.rethrowAsRuntimeException();
}
@@ -428,7 +439,8 @@ public class RootWindowContainerTests extends WindowTestsBase {
final Rect bounds = new Rect(task.getBounds());
bounds.scale(0.5f);
task.setBounds(bounds);
- assertFalse(activity.isLetterboxedForFixedOrientationAndAspectRatio());
+ assertFalse(activity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio());
assertThat(task.autoRemoveRecents).isFalse();
}
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 64527cb63e45..ae88b1baa5b8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -64,6 +64,7 @@ import static com.android.server.wm.ActivityRecord.State.PAUSED;
import static com.android.server.wm.ActivityRecord.State.RESTARTING_PROCESS;
import static com.android.server.wm.ActivityRecord.State.RESUMED;
import static com.android.server.wm.ActivityRecord.State.STOPPED;
+import static com.android.server.wm.AppCompatUtils.computeAspectRatio;
import static com.android.server.wm.DisplayContent.IME_TARGET_LAYERING;
import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_POSITION_MULTIPLIER_CENTER;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
@@ -103,6 +104,7 @@ import android.graphics.Rect;
import android.os.Binder;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.annotations.Presubmit;
import android.provider.DeviceConfig;
@@ -494,7 +496,7 @@ public class SizeCompatTests extends WindowTestsBase {
// Activity is sandboxed; it is in size compat mode since it is not resizable and has a
// max aspect ratio.
assertActivityMaxBoundsSandboxed();
- assertScaled();
+ assertDownScaled();
}
@Test
@@ -514,7 +516,7 @@ public class SizeCompatTests extends WindowTestsBase {
// The bounds should be [100, 0 - 1100, 2500].
assertEquals(origBounds.width(), currentBounds.width());
assertEquals(origBounds.height(), currentBounds.height());
- assertScaled();
+ assertDownScaled();
// The scale is 2000/2500=0.8. The horizontal centered offset is (1000-(1000*0.8))/2=100.
final float scale = (float) display.mBaseDisplayHeight / currentBounds.height();
@@ -554,7 +556,7 @@ public class SizeCompatTests extends WindowTestsBase {
assertEquals(origBounds.width(), currentBounds.width());
assertEquals(origBounds.height(), currentBounds.height());
assertEquals(offsetX, mActivity.getBounds().left);
- assertScaled();
+ assertDownScaled();
// Activity is sandboxed due to size compat mode.
assertActivityMaxBoundsSandboxed();
@@ -692,7 +694,7 @@ public class SizeCompatTests extends WindowTestsBase {
// The configuration bounds [820, 0 - 1820, 2500] should keep the same.
assertEquals(originalBounds.width(), currentBounds.width());
assertEquals(originalBounds.height(), currentBounds.height());
- assertScaled();
+ assertDownScaled();
// Activity max bounds are sandboxed due to size compat mode on the new display.
assertActivityMaxBoundsSandboxed();
@@ -751,7 +753,7 @@ public class SizeCompatTests extends WindowTestsBase {
assertEquals(origAppBounds.width(), appBounds.width());
assertEquals(origAppBounds.height(), appBounds.height());
// The activity is 1000x1400 and the display is 2500x1000.
- assertScaled();
+ assertDownScaled();
final float scale = mActivity.getCompatScale();
// The position in configuration should be in app coordinates.
final Rect screenBounds = mActivity.getBounds();
@@ -848,7 +850,7 @@ public class SizeCompatTests extends WindowTestsBase {
// Size compatibility mode is able to handle orientation change so the process shouldn't be
// restarted and the override configuration won't be cleared.
verify(mActivity, never()).restartProcessIfVisible();
- assertScaled();
+ assertDownScaled();
// Activity max bounds are sandboxed due to size compat mode, even if is not visible.
assertActivityMaxBoundsSandboxed();
@@ -1081,10 +1083,11 @@ public class SizeCompatTests extends WindowTestsBase {
// Simulate the user selecting the fullscreen user aspect ratio override
spyOn(activity.mWmService.mLetterboxConfiguration);
- spyOn(activity.mLetterboxUiController);
+ spyOn(activity.mAppCompatController.getAppCompatAspectRatioOverrides());
doReturn(true).when(activity.mWmService.mLetterboxConfiguration)
.isUserAppAspectRatioFullscreenEnabled();
- doReturn(USER_MIN_ASPECT_RATIO_FULLSCREEN).when(activity.mLetterboxUiController)
+ doReturn(USER_MIN_ASPECT_RATIO_FULLSCREEN)
+ .when(activity.mAppCompatController.getAppCompatAspectRatioOverrides())
.getUserMinAspectRatioOverrideCode();
assertFalse(activity.shouldCreateCompatDisplayInsets());
}
@@ -1102,9 +1105,10 @@ public class SizeCompatTests extends WindowTestsBase {
RESIZE_MODE_UNRESIZEABLE, ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
// Simulate the user selecting the fullscreen user aspect ratio override
- spyOn(activity.mLetterboxUiController);
- doReturn(true).when(activity.mLetterboxUiController)
- .isSystemOverrideToFullscreenEnabled();
+ spyOn(activity.mAppCompatController.getAppCompatAspectRatioOverrides());
+ doReturn(true).when(
+ activity.mAppCompatController.getAppCompatAspectRatioOverrides())
+ .isSystemOverrideToFullscreenEnabled();
assertFalse(activity.shouldCreateCompatDisplayInsets());
}
@@ -1123,7 +1127,8 @@ public class SizeCompatTests extends WindowTestsBase {
prepareUnresizable(activity, /* maxAspect=*/ 1.5f, SCREEN_ORIENTATION_LANDSCAPE);
// Activity max bounds should not be sandboxed, even though it is letterboxed.
- assertTrue(activity.isLetterboxedForFixedOrientationAndAspectRatio());
+ assertTrue(activity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio());
assertThat(activity.getConfiguration().windowConfiguration.getMaxBounds())
.isEqualTo(activity.getDisplayArea().getBounds());
}
@@ -1164,7 +1169,8 @@ public class SizeCompatTests extends WindowTestsBase {
prepareUnresizable(activity, /* maxAspect=*/ 1.5f, SCREEN_ORIENTATION_LANDSCAPE);
// Activity max bounds should not be sandboxed, even though it is letterboxed.
- assertTrue(activity.isLetterboxedForFixedOrientationAndAspectRatio());
+ assertTrue(activity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio());
assertThat(activity.getConfiguration().windowConfiguration.getMaxBounds())
.isEqualTo(activity.getDisplayArea().getBounds());
}
@@ -1187,7 +1193,8 @@ public class SizeCompatTests extends WindowTestsBase {
prepareUnresizable(activity, /* maxAspect=*/ 1.5f, SCREEN_ORIENTATION_LANDSCAPE);
// Activity max bounds should not be sandboxed, even though it is letterboxed.
- assertTrue(activity.isLetterboxedForFixedOrientationAndAspectRatio());
+ assertTrue(activity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio());
assertThat(activity.getConfiguration().windowConfiguration.getMaxBounds())
.isEqualTo(activity.getDisplayArea().getBounds());
}
@@ -1618,6 +1625,85 @@ public class SizeCompatTests extends WindowTestsBase {
activity.getBounds().width(), 0.5);
}
+
+ /**
+ * Test that a freeform unresizeable activity can be down-scaled to fill its smaller parent
+ * bounds.
+ */
+ @Test
+ public void testCompatScaling_freeformUnresizeableApp_largerThanParent_downScaled() {
+ final int dw = 600;
+ final int dh = 800;
+ final DisplayContent display = new TestDisplayContent.Builder(mAtm, dw, dh)
+ .setWindowingMode(WINDOWING_MODE_FREEFORM)
+ .build();
+ setUpApp(display);
+ prepareUnresizable(mActivity, /* maxAspect */ 0f, SCREEN_ORIENTATION_PORTRAIT);
+ mActivity.setWindowingMode(WINDOWING_MODE_FREEFORM);
+ assertFalse(mActivity.inSizeCompatMode());
+
+ // Resize app to make original app bounds larger than parent bounds.
+ mTask.getWindowConfiguration().setAppBounds(
+ new Rect(0, 0, dw - 300, dh - 400));
+ mActivity.onConfigurationChanged(mTask.getConfiguration());
+ // App should enter size compat mode and be down-scaled to fill new parent bounds.
+ assertDownScaled();
+ }
+
+ /**
+ * Test that when desktop mode is enabled, a freeform unresizeable activity can be up-scaled to
+ * fill its larger parent bounds.
+ */
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
+ public void testCompatScaling_freeformUnresizeableApp_smallerThanParent_upScaled() {
+ doReturn(true).when(() ->
+ DesktopModeLaunchParamsModifier.canEnterDesktopMode(any()));
+ final int dw = 600;
+ final int dh = 800;
+ final DisplayContent display = new TestDisplayContent.Builder(mAtm, dw, dh)
+ .setWindowingMode(WINDOWING_MODE_FREEFORM)
+ .build();
+ setUpApp(display);
+ prepareUnresizable(mActivity, /* maxAspect */ 0f, SCREEN_ORIENTATION_PORTRAIT);
+ mActivity.setWindowingMode(WINDOWING_MODE_FREEFORM);
+ assertFalse(mActivity.inSizeCompatMode());
+
+ // Resize app to make original app bounds smaller than parent bounds.
+ mTask.getWindowConfiguration().setAppBounds(
+ new Rect(0, 0, dw + 300, dh + 400));
+ mActivity.onConfigurationChanged(mTask.getConfiguration());
+ // App should enter size compat mode and be up-scaled to fill parent bounds.
+ assertUpScaled();
+ }
+
+ /**
+ * Test that when desktop mode is disabled, a freeform unresizeable activity cannot be up-scaled
+ * despite its larger parent bounds.
+ */
+ @Test
+ @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
+ public void testSizeCompatScaling_freeformUnresizeableApp_smallerThanParent_notScaled() {
+ final int dw = 600;
+ final int dh = 800;
+ final DisplayContent display = new TestDisplayContent.Builder(mAtm, dw, dh)
+ .setWindowingMode(WINDOWING_MODE_FREEFORM)
+ .build();
+ setUpApp(display);
+ prepareUnresizable(mActivity, /* maxAspect */ 0f, SCREEN_ORIENTATION_PORTRAIT);
+ mActivity.setWindowingMode(WINDOWING_MODE_FREEFORM);
+ assertFalse(mActivity.inSizeCompatMode());
+ final Rect originalAppBounds = mActivity.getBounds();
+
+ // Resize app to make original app bounds smaller than parent bounds.
+ mTask.getWindowConfiguration().setAppBounds(
+ new Rect(0, 0, dw + 300, dh + 400));
+ mActivity.onConfigurationChanged(mTask.getConfiguration());
+ // App should enter size compat mode but remain its original size.
+ assertTrue(mActivity.inSizeCompatMode());
+ assertEquals(originalAppBounds, mActivity.getBounds());
+ }
+
@Test
public void testGetLetterboxInnerBounds_noScalingApplied() {
// Set up a display in portrait and ignoring orientation request.
@@ -1636,7 +1722,8 @@ public class SizeCompatTests extends WindowTestsBase {
addWindowToActivity(mActivity);
// App should launch in fullscreen.
- assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
+ assertFalse(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(mActivity.inSizeCompatMode());
// Activity inherits max bounds from TaskDisplayArea.
@@ -1650,8 +1737,9 @@ public class SizeCompatTests extends WindowTestsBase {
assertTrue(rotatedDisplayBounds.width() < rotatedDisplayBounds.height());
// App should be in size compat.
- assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
- assertScaled();
+ assertFalse(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio());
+ assertDownScaled();
assertThat(mActivity.inSizeCompatMode()).isTrue();
assertActivityMaxBoundsSandboxed();
@@ -1762,7 +1850,8 @@ public class SizeCompatTests extends WindowTestsBase {
assertTrue(displayBounds.width() > displayBounds.height());
// App should launch in fixed orientation letterbox.
- assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
+ assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(mActivity.inSizeCompatMode());
assertActivityMaxBoundsSandboxed();
@@ -1793,7 +1882,8 @@ public class SizeCompatTests extends WindowTestsBase {
assertTrue(displayBounds.width() > displayBounds.height());
// App should launch in fixed orientation letterbox.
- assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
+ assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(mActivity.inSizeCompatMode());
// Activity bounds should respect minimum aspect ratio for activity.
@@ -1823,7 +1913,8 @@ public class SizeCompatTests extends WindowTestsBase {
assertTrue(displayBounds.width() > displayBounds.height());
// App should launch in fixed orientation letterbox.
- assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
+ assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(mActivity.inSizeCompatMode());
// Activity bounds should respect maximum aspect ratio for activity.
@@ -1853,7 +1944,8 @@ public class SizeCompatTests extends WindowTestsBase {
assertTrue(displayBounds.width() > displayBounds.height());
// App should launch in fixed orientation letterbox.
- assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
+ assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(mActivity.inSizeCompatMode());
// Activity bounds should respect aspect ratio override for fixed orientation letterbox.
@@ -1950,7 +2042,8 @@ public class SizeCompatTests extends WindowTestsBase {
assertTrue(displayBounds.width() > displayBounds.height());
// App should launch in fixed orientation letterbox.
- assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
+ assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(mActivity.inSizeCompatMode());
// Letterbox logic should use config_letterboxDefaultMinAspectRatioForUnresizableApps over
@@ -1976,7 +2069,8 @@ public class SizeCompatTests extends WindowTestsBase {
// App should launch in fixed orientation letterbox.
// Activity bounds should be 700x1400 with the ratio as the display.
- assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
+ assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio());
assertFitted();
assertEquals(originalScreenWidthDp, mActivity.getConfiguration().smallestScreenWidthDp);
assertTrue(originalScreenWidthDp < originalScreenHeighthDp);
@@ -1986,7 +2080,7 @@ public class SizeCompatTests extends WindowTestsBase {
// After we rotate, the activity should go in the size-compat mode and report the same
// configuration values.
- assertScaled();
+ assertDownScaled();
assertEquals(originalScreenWidthDp, mActivity.getConfiguration().smallestScreenWidthDp);
assertEquals(originalScreenWidthDp, mActivity.getConfiguration().screenWidthDp);
assertEquals(originalScreenHeighthDp, mActivity.getConfiguration().screenHeightDp);
@@ -2018,7 +2112,8 @@ public class SizeCompatTests extends WindowTestsBase {
// App should launch in fixed orientation letterbox.
// Activity bounds should be 700x1400 with the ratio as the display.
- assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
+ assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio());
assertFitted();
assertEquals(originalScreenWidthDp, mActivity.getConfiguration().smallestScreenWidthDp);
assertTrue(originalScreenWidthDp < originalScreenHeighthDp);
@@ -2052,7 +2147,8 @@ public class SizeCompatTests extends WindowTestsBase {
final Rect activityBounds = new Rect(mActivity.getBounds());
// App should launch in fixed orientation letterbox.
- assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
+ assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio());
// Checking that there is no size compat mode.
assertFitted();
@@ -2081,9 +2177,10 @@ public class SizeCompatTests extends WindowTestsBase {
.isUserAppAspectRatioFullscreenEnabled();
// Set user aspect ratio override
- spyOn(mActivity.mLetterboxUiController);
- doReturn(USER_MIN_ASPECT_RATIO_FULLSCREEN).when(mActivity.mLetterboxUiController)
- .getUserMinAspectRatioOverrideCode();
+ spyOn(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides());
+ doReturn(USER_MIN_ASPECT_RATIO_FULLSCREEN)
+ .when(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides())
+ .getUserMinAspectRatioOverrideCode();
prepareMinAspectRatio(mActivity, 16 / 9f, SCREEN_ORIENTATION_PORTRAIT);
@@ -2105,9 +2202,10 @@ public class SizeCompatTests extends WindowTestsBase {
.isUserAppAspectRatioFullscreenEnabled();
// Set user aspect ratio override
- spyOn(mActivity.mLetterboxUiController);
- doReturn(USER_MIN_ASPECT_RATIO_FULLSCREEN).when(mActivity.mLetterboxUiController)
- .getUserMinAspectRatioOverrideCode();
+ spyOn(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides());
+ doReturn(USER_MIN_ASPECT_RATIO_FULLSCREEN)
+ .when(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides())
+ .getUserMinAspectRatioOverrideCode();
prepareMinAspectRatio(mActivity, 16 / 9f, SCREEN_ORIENTATION_LANDSCAPE);
@@ -2124,9 +2222,10 @@ public class SizeCompatTests extends WindowTestsBase {
final int displayHeight = 1400;
setUpDisplaySizeWithApp(displayWidth, displayHeight);
mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
- spyOn(mActivity.mLetterboxUiController);
- doReturn(true).when(mActivity.mLetterboxUiController)
- .isSystemOverrideToFullscreenEnabled();
+ spyOn(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides());
+ doReturn(true).when(
+ mActivity.mAppCompatController.getAppCompatAspectRatioOverrides())
+ .isSystemOverrideToFullscreenEnabled();
prepareMinAspectRatio(mActivity, 16 / 9f, SCREEN_ORIENTATION_PORTRAIT);
@@ -2143,9 +2242,10 @@ public class SizeCompatTests extends WindowTestsBase {
final int displayHeight = 1600;
setUpDisplaySizeWithApp(displayWidth, displayHeight);
mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
- spyOn(mActivity.mLetterboxUiController);
- doReturn(true).when(mActivity.mLetterboxUiController)
- .isSystemOverrideToFullscreenEnabled();
+ spyOn(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides());
+ doReturn(true).when(
+ mActivity.mAppCompatController.getAppCompatAspectRatioOverrides())
+ .isSystemOverrideToFullscreenEnabled();
prepareMinAspectRatio(mActivity, 16 / 9f, SCREEN_ORIENTATION_LANDSCAPE);
@@ -2588,7 +2688,8 @@ public class SizeCompatTests extends WindowTestsBase {
final Rect activityBounds = new Rect(mActivity.getBounds());
// App should launch in fixed orientation letterbox.
- assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
+ assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio());
// Checking that there is no size compat mode.
assertFitted();
@@ -2632,13 +2733,14 @@ public class SizeCompatTests extends WindowTestsBase {
assertEquals(WINDOWING_MODE_MULTI_WINDOW, mActivity.getWindowingMode());
// App should launch in fixed orientation letterbox.
- assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
+ assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio());
// Checking that there is no size compat mode.
assertFitted();
// Check that the display aspect ratio is used by the app.
final float targetMinAspectRatio = 1f * displayHeight / displayWidth;
- assertEquals(targetMinAspectRatio, ActivityRecord
- .computeAspectRatio(mActivity.getBounds()), DELTA_ASPECT_RATIO_TOLERANCE);
+ assertEquals(targetMinAspectRatio, computeAspectRatio(mActivity.getBounds()),
+ DELTA_ASPECT_RATIO_TOLERANCE);
}
@Test
@@ -2667,13 +2769,14 @@ public class SizeCompatTests extends WindowTestsBase {
assertEquals(WINDOWING_MODE_MULTI_WINDOW, mActivity.getWindowingMode());
// App should launch in fixed orientation letterbox.
- assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
+ assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio());
// Checking that there is no size compat mode.
assertFitted();
// Check that the display aspect ratio is used by the app.
final float targetMinAspectRatio = 1f * displayWidth / displayHeight;
- assertEquals(targetMinAspectRatio, ActivityRecord
- .computeAspectRatio(mActivity.getBounds()), DELTA_ASPECT_RATIO_TOLERANCE);
+ assertEquals(targetMinAspectRatio, computeAspectRatio(mActivity.getBounds()),
+ DELTA_ASPECT_RATIO_TOLERANCE);
}
@Test
@@ -2693,13 +2796,14 @@ public class SizeCompatTests extends WindowTestsBase {
prepareUnresizable(mActivity, SCREEN_ORIENTATION_LANDSCAPE);
// App should launch in fixed orientation letterbox.
- assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
+ assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio());
// Checking that there is no size compat mode.
assertFitted();
// Check that the display aspect ratio is used by the app.
final float targetMinAspectRatio = 1f * displayHeight / displayWidth;
- assertEquals(targetMinAspectRatio, ActivityRecord
- .computeAspectRatio(mActivity.getBounds()), DELTA_ASPECT_RATIO_TOLERANCE);
+ assertEquals(targetMinAspectRatio, computeAspectRatio(mActivity.getBounds()),
+ DELTA_ASPECT_RATIO_TOLERANCE);
}
@Test
@@ -2719,13 +2823,14 @@ public class SizeCompatTests extends WindowTestsBase {
prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT);
// App should launch in fixed orientation letterbox.
- assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
+ assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio());
// Checking that there is no size compat mode.
assertFitted();
// Check that the display aspect ratio is used by the app.
final float targetMinAspectRatio = 1f * displayWidth / displayHeight;
- assertEquals(targetMinAspectRatio, ActivityRecord
- .computeAspectRatio(mActivity.getBounds()), DELTA_ASPECT_RATIO_TOLERANCE);
+ assertEquals(targetMinAspectRatio, computeAspectRatio(mActivity.getBounds()),
+ DELTA_ASPECT_RATIO_TOLERANCE);
}
@Test
@@ -2748,8 +2853,9 @@ public class SizeCompatTests extends WindowTestsBase {
assertTrue(displayBounds.width() < displayBounds.height());
// App should be in size compat.
- assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
- assertScaled();
+ assertFalse(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio());
+ assertDownScaled();
assertEquals(activityBounds.width(), newActivityBounds.width());
assertEquals(activityBounds.height(), newActivityBounds.height());
assertActivityMaxBoundsSandboxed();
@@ -2765,7 +2871,8 @@ public class SizeCompatTests extends WindowTestsBase {
prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_PORTRAIT);
// App should launch in fullscreen.
- assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
+ assertFalse(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(mActivity.inSizeCompatMode());
// Activity inherits max bounds from TaskDisplayArea.
assertMaxBoundsInheritDisplayAreaBounds();
@@ -2778,8 +2885,9 @@ public class SizeCompatTests extends WindowTestsBase {
assertTrue(rotatedDisplayBounds.width() > rotatedDisplayBounds.height());
// App should be in size compat.
- assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
- assertScaled();
+ assertFalse(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio());
+ assertDownScaled();
assertThat(mActivity.inSizeCompatMode()).isTrue();
assertActivityMaxBoundsSandboxed();
@@ -2799,7 +2907,8 @@ public class SizeCompatTests extends WindowTestsBase {
// Portrait fixed app without max aspect.
prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_PORTRAIT);
- assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
+ assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(mActivity.inSizeCompatMode());
// Launch another portrait fixed app.
@@ -2821,7 +2930,8 @@ public class SizeCompatTests extends WindowTestsBase {
// Task and display bounds should be equal while activity should be letterboxed and
// has 700x1400 bounds with the ratio as the display.
- assertTrue(newActivity.isLetterboxedForFixedOrientationAndAspectRatio());
+ assertTrue(newActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(newActivity.inSizeCompatMode());
// Activity max bounds are sandboxed due to size compat mode.
assertThat(newActivity.getConfiguration().windowConfiguration.getMaxBounds())
@@ -2842,7 +2952,8 @@ public class SizeCompatTests extends WindowTestsBase {
// Portrait fixed app without max aspect.
prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_PORTRAIT);
- assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
+ assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(mActivity.inSizeCompatMode());
mActivity.setRequestedOrientation(SCREEN_ORIENTATION_UNSPECIFIED);
@@ -2863,7 +2974,8 @@ public class SizeCompatTests extends WindowTestsBase {
// Portrait fixed app without max aspect.
prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_PORTRAIT);
- assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
+ assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(mActivity.inSizeCompatMode());
// Launch another portrait fixed app with max aspect ratio as 1.3.
@@ -2893,7 +3005,8 @@ public class SizeCompatTests extends WindowTestsBase {
assertActivityMaxBoundsSandboxed();
// Activity bounds should be (1400 / 1.3 = 1076)x1400 with the app requested ratio.
- assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
+ assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(newActivity.inSizeCompatMode());
assertEquals(displayBounds.height(), newActivityBounds.height());
assertEquals((long) Math.rint(newActivityBounds.height()
@@ -2912,15 +3025,17 @@ public class SizeCompatTests extends WindowTestsBase {
prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_PORTRAIT);
clearInvocations(mActivity);
- assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
+ assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(mActivity.inSizeCompatMode());
// Rotate display to portrait.
rotateDisplay(mActivity.mDisplayContent, ROTATION_90);
// App should be in size compat.
- assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
- assertScaled();
+ assertFalse(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio());
+ assertDownScaled();
assertThat(mActivity.inSizeCompatMode()).isTrue();
// Activity max bounds are sandboxed due to size compat mode.
assertActivityMaxBoundsSandboxed();
@@ -2930,8 +3045,9 @@ public class SizeCompatTests extends WindowTestsBase {
// App still in size compat, and the bounds don't change.
verify(mActivity, never()).clearSizeCompatMode();
- assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
- assertScaled();
+ assertFalse(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio());
+ assertDownScaled();
assertEquals(activityBounds, mActivity.getBounds());
// Activity max bounds are sandboxed due to size compat.
assertActivityMaxBoundsSandboxed();
@@ -2948,7 +3064,8 @@ public class SizeCompatTests extends WindowTestsBase {
prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_PORTRAIT);
// In fixed orientation letterbox
- assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
+ assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(mActivity.inSizeCompatMode());
assertActivityMaxBoundsSandboxed();
@@ -2956,15 +3073,17 @@ public class SizeCompatTests extends WindowTestsBase {
rotateDisplay(display, ROTATION_90);
// App should be in size compat.
- assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
- assertScaled();
+ assertFalse(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio());
+ assertDownScaled();
assertActivityMaxBoundsSandboxed();
// Rotate display to landscape.
rotateDisplay(display, ROTATION_180);
// In activity letterbox
- assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
+ assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(mActivity.inSizeCompatMode());
assertActivityMaxBoundsSandboxed();
}
@@ -2982,7 +3101,8 @@ public class SizeCompatTests extends WindowTestsBase {
prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_LANDSCAPE);
// In fixed orientation letterbox
- assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
+ assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(mActivity.inSizeCompatMode());
assertActivityMaxBoundsSandboxed();
@@ -2990,15 +3110,17 @@ public class SizeCompatTests extends WindowTestsBase {
rotateDisplay(display, ROTATION_90);
// App should be in size compat.
- assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
- assertScaled();
+ assertFalse(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio());
+ assertDownScaled();
assertActivityMaxBoundsSandboxed();
// Rotate display to portrait.
rotateDisplay(display, ROTATION_180);
// In fixed orientation letterbox
- assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
+ assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(mActivity.inSizeCompatMode());
assertActivityMaxBoundsSandboxed();
}
@@ -3182,7 +3304,7 @@ public class SizeCompatTests extends WindowTestsBase {
assertEquals(WINDOWING_MODE_MULTI_WINDOW, mActivity.getWindowingMode());
// Non-resizable activity in size compat mode
- assertScaled();
+ assertDownScaled();
final Rect newBounds = new Rect(mActivity.getWindowConfiguration().getBounds());
assertEquals(originalBounds.width(), newBounds.width());
assertEquals(originalBounds.height(), newBounds.height());
@@ -3195,7 +3317,8 @@ public class SizeCompatTests extends WindowTestsBase {
assertEquals(ORIENTATION_PORTRAIT, mTask.getConfiguration().orientation);
assertEquals(ORIENTATION_LANDSCAPE, mActivity.getConfiguration().orientation);
assertFitted();
- assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
+ assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio());
assertActivityMaxBoundsSandboxed();
// Letterbox should fill the gap between the split screen and the letterboxed activity.
@@ -3221,7 +3344,8 @@ public class SizeCompatTests extends WindowTestsBase {
// Resizable activity is not in size compat mode but in the letterbox for fixed orientation.
assertFitted();
- assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
+ assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio());
}
@Test
@@ -3244,7 +3368,7 @@ public class SizeCompatTests extends WindowTestsBase {
assertEquals(WINDOWING_MODE_MULTI_WINDOW, mActivity.getWindowingMode());
// Non-resizable activity in size compat mode
- assertScaled();
+ assertDownScaled();
final Rect newBounds = new Rect(mActivity.getWindowConfiguration().getBounds());
assertEquals(originalBounds.width(), newBounds.width());
assertEquals(originalBounds.height(), newBounds.height());
@@ -3257,7 +3381,8 @@ public class SizeCompatTests extends WindowTestsBase {
assertEquals(ORIENTATION_PORTRAIT, mTask.getConfiguration().orientation);
assertEquals(ORIENTATION_PORTRAIT, mActivity.getConfiguration().orientation);
assertFitted();
- assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
+ assertFalse(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio());
assertActivityMaxBoundsSandboxed();
// Activity bounds fill split screen.
@@ -3284,7 +3409,7 @@ public class SizeCompatTests extends WindowTestsBase {
organizer.mPrimary.setBounds(0, 0, 1000, 800);
// Non-resizable activity should be in size compat mode.
- assertScaled();
+ assertDownScaled();
assertEquals(mActivity.getBounds(), new Rect(60, 0, 940, 800));
recomputeNaturalConfigurationOfUnresizableActivity();
@@ -3861,7 +3986,7 @@ public class SizeCompatTests extends WindowTestsBase {
// Force activity to scaled down for size compat mode.
resizeDisplay(mTask.mDisplayContent, 700, 1400);
assertTrue(mActivity.inSizeCompatMode());
- assertScaled();
+ assertDownScaled();
assertEquals(sizeCompatScaled, mActivity.getBounds());
}
@@ -3892,7 +4017,8 @@ public class SizeCompatTests extends WindowTestsBase {
// orientation is not respected with insets as insets have been decoupled.
final Rect appBounds = activity.getWindowConfiguration().getAppBounds();
final Rect displayBounds = display.getBounds();
- assertFalse(activity.isLetterboxedForFixedOrientationAndAspectRatio());
+ assertFalse(activity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio());
assertNotNull(appBounds);
assertEquals(displayBounds.width(), appBounds.width());
assertEquals(displayBounds.height(), appBounds.height());
@@ -3923,7 +4049,8 @@ public class SizeCompatTests extends WindowTestsBase {
final Rect bounds = activity.getBounds();
// Activity should be letterboxed and should have portrait app bounds
- assertTrue(activity.isLetterboxedForFixedOrientationAndAspectRatio());
+ assertTrue(activity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio());
assertTrue(bounds.height() > bounds.width());
}
@@ -3957,7 +4084,8 @@ public class SizeCompatTests extends WindowTestsBase {
assertNotNull(activity.getCompatDisplayInsets());
// Activity is not letterboxed for fixed orientation because orientation is respected
// with insets, and should not be in size compat mode
- assertFalse(activity.isLetterboxedForFixedOrientationAndAspectRatio());
+ assertFalse(activity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(activity.inSizeCompatMode());
}
@@ -4204,9 +4332,10 @@ public class SizeCompatTests extends WindowTestsBase {
Configuration parentConfig = mActivity.getParent().getConfiguration();
- float actual = mActivity.mLetterboxUiController
- .getFixedOrientationLetterboxAspectRatio(parentConfig);
- float expected = mActivity.mLetterboxUiController.getSplitScreenAspectRatio();
+ final AppCompatAspectRatioOverrides aspectRatioOverrides =
+ mActivity.mAppCompatController.getAppCompatAspectRatioOverrides();
+ float actual = aspectRatioOverrides.getFixedOrientationLetterboxAspectRatio(parentConfig);
+ float expected = aspectRatioOverrides.getSplitScreenAspectRatio();
assertEquals(expected, actual, DELTA_ASPECT_RATIO_TOLERANCE);
}
@@ -4357,7 +4486,7 @@ public class SizeCompatTests extends WindowTestsBase {
resizeDisplay(mTask.mDisplayContent, 1400, 700);
assertTrue(mActivity.inSizeCompatMode());
- assertScaled();
+ assertDownScaled();
assertEquals(sizeCompatScaled, mActivity.getBounds());
}
@@ -4380,7 +4509,8 @@ public class SizeCompatTests extends WindowTestsBase {
verifyLogAppCompatState(mActivity, APP_COMPAT_STATE_CHANGED__STATE__NOT_LETTERBOXED);
prepareUnresizable(mActivity, /* maxAspect= */ 2, SCREEN_ORIENTATION_PORTRAIT);
- assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
+ assertFalse(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(mActivity.inSizeCompatMode());
assertTrue(mActivity.areBoundsLetterboxed());
@@ -4396,7 +4526,8 @@ public class SizeCompatTests extends WindowTestsBase {
// ActivityRecord#resolveSizeCompatModeConfiguration because mCompatDisplayInsets aren't
// null but activity doesn't enter size compat mode. Checking that areBoundsLetterboxed()
// still returns true because of the aspect ratio restrictions.
- assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
+ assertFalse(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(mActivity.inSizeCompatMode());
assertTrue(mActivity.areBoundsLetterboxed());
verifyLogAppCompatState(mActivity,
@@ -4423,7 +4554,8 @@ public class SizeCompatTests extends WindowTestsBase {
prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT);
- assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
+ assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(mActivity.inSizeCompatMode());
assertTrue(mActivity.areBoundsLetterboxed());
verifyLogAppCompatState(mActivity,
@@ -4441,7 +4573,8 @@ public class SizeCompatTests extends WindowTestsBase {
rotateDisplay(mActivity.mDisplayContent, ROTATION_90);
- assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
+ assertFalse(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio());
assertTrue(mActivity.inSizeCompatMode());
assertTrue(mActivity.areBoundsLetterboxed());
verifyLogAppCompatState(mActivity,
@@ -4502,7 +4635,8 @@ public class SizeCompatTests extends WindowTestsBase {
prepareUnresizable(mActivity, SCREEN_ORIENTATION_LANDSCAPE);
assertFalse(mActivity.isEligibleForLetterboxEducation());
- assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
+ assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio());
}
@Test
@@ -4560,7 +4694,8 @@ public class SizeCompatTests extends WindowTestsBase {
prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT);
assertTrue(mActivity.isEligibleForLetterboxEducation());
- assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
+ assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio());
}
@Test
@@ -4574,7 +4709,8 @@ public class SizeCompatTests extends WindowTestsBase {
rotateDisplay(mActivity.mDisplayContent, ROTATION_90);
assertTrue(mActivity.isEligibleForLetterboxEducation());
- assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
+ assertFalse(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio());
assertTrue(mActivity.inSizeCompatMode());
}
@@ -4616,7 +4752,7 @@ public class SizeCompatTests extends WindowTestsBase {
// Target min aspect ratio must be larger than parent aspect ratio to be applied.
final float targetMinAspectRatio = 3.0f;
- // Create fixed portait activity with min aspect ratio greater than parent aspect ratio.
+ // Create fixed portrait activity with min aspect ratio greater than parent aspect ratio.
final ActivityRecord fixedOrientationActivity = new ActivityBuilder(mAtm)
.setTask(task).setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT)
.setMinAspectRatio(targetMinAspectRatio).build();
@@ -4630,7 +4766,7 @@ public class SizeCompatTests extends WindowTestsBase {
final Rect minAspectRatioAppBounds = new Rect(minAspectRatioActivity.getConfiguration()
.windowConfiguration.getAppBounds());
- // Create unresizeable fixed portait activity with min aspect ratio greater than parent
+ // Create unresizeable fixed portrait activity with min aspect ratio greater than parent
// aspect ratio.
final ActivityRecord sizeCompatActivity = new ActivityBuilder(mAtm)
.setTask(task).setResizeMode(RESIZE_MODE_UNRESIZEABLE)
@@ -4642,12 +4778,12 @@ public class SizeCompatTests extends WindowTestsBase {
.windowConfiguration.getAppBounds());
// Check that aspect ratio of app bounds is equal to the min aspect ratio.
- assertEquals(targetMinAspectRatio, ActivityRecord
- .computeAspectRatio(fixedOrientationAppBounds), DELTA_ASPECT_RATIO_TOLERANCE);
- assertEquals(targetMinAspectRatio, ActivityRecord
- .computeAspectRatio(minAspectRatioAppBounds), DELTA_ASPECT_RATIO_TOLERANCE);
- assertEquals(targetMinAspectRatio, ActivityRecord
- .computeAspectRatio(sizeCompatAppBounds), DELTA_ASPECT_RATIO_TOLERANCE);
+ assertEquals(targetMinAspectRatio,
+ computeAspectRatio(fixedOrientationAppBounds), DELTA_ASPECT_RATIO_TOLERANCE);
+ assertEquals(targetMinAspectRatio,
+ computeAspectRatio(minAspectRatioAppBounds), DELTA_ASPECT_RATIO_TOLERANCE);
+ assertEquals(targetMinAspectRatio,
+ computeAspectRatio(sizeCompatAppBounds), DELTA_ASPECT_RATIO_TOLERANCE);
}
@Test
@@ -4663,7 +4799,7 @@ public class SizeCompatTests extends WindowTestsBase {
// Activity should enter size compat with old density after display density change.
display.setForcedDensity(newDensity, UserHandle.USER_CURRENT);
- assertScaled();
+ assertDownScaled();
assertEquals(origDensity, mActivity.getConfiguration().densityDpi);
// Activity should exit size compat with new density.
@@ -4902,14 +5038,25 @@ public class SizeCompatTests extends WindowTestsBase {
}
}
- private void assertScaled() {
- assertScaled(mActivity);
+ private void assertUpScaled() {
+ assertScaled(mActivity, /* upScalingExpected */ true);
}
- /** Asserts that the size of activity is larger than its parent so it is scaling. */
- private void assertScaled(ActivityRecord activity) {
+ private void assertDownScaled() {
+ assertScaled(mActivity, /* upScalingExpected */ false);
+ }
+
+ /**
+ * Asserts that the size of an activity differs from its parent and so it is scaling (either up
+ * or down).
+ */
+ private void assertScaled(ActivityRecord activity, boolean upScalingExpected) {
assertTrue(activity.inSizeCompatMode());
- assertNotEquals(1f, activity.getCompatScale(), 0.0001f /* delta */);
+ if (upScalingExpected) {
+ assertTrue(activity.getCompatScale() > 1f);
+ } else {
+ assertTrue(activity.getCompatScale() < 1f);
+ }
}
private void assertFitted() {
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 a71b81e025d2..d013053a063d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
@@ -90,7 +90,6 @@ import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
-import android.view.RemoteAnimationDefinition;
import android.view.SurfaceControl;
import android.window.IRemoteTransition;
import android.window.ITaskFragmentOrganizer;
@@ -140,7 +139,6 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
private IBinder mFragmentToken;
private WindowContainerTransaction mTransaction;
private WindowContainerToken mFragmentWindowToken;
- private RemoteAnimationDefinition mDefinition;
private IBinder mErrorToken;
private Rect mTaskFragBounds;
@@ -169,7 +167,6 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
mTransaction = new WindowContainerTransaction();
mTransaction.setTaskFragmentOrganizer(mIOrganizer);
mFragmentWindowToken = mTaskFragment.mRemoteToken.toWindowContainerToken();
- mDefinition = new RemoteAnimationDefinition();
mErrorToken = new Binder();
final Rect displayBounds = mDisplayContent.getBounds();
mTaskFragBounds = new Rect(displayBounds.left, displayBounds.top, displayBounds.centerX(),
@@ -579,17 +576,6 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
}
@Test
- public void testRegisterRemoteAnimations() {
- mController.registerRemoteAnimations(mIOrganizer, mDefinition);
-
- assertEquals(mDefinition, mController.getRemoteAnimationDefinition(mIOrganizer));
-
- mController.unregisterRemoteAnimations(mIOrganizer);
-
- assertNull(mController.getRemoteAnimationDefinition(mIOrganizer));
- }
-
- @Test
public void testApplyTransaction_disallowRemoteTransitionForNonSystemOrganizer() {
mTransaction.setRelativeBounds(mFragmentWindowToken, new Rect(0, 0, 100, 100));
mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* uid */,
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
index 35b6b70cb611..47d34a6e5f2b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
@@ -759,20 +759,24 @@ public class TaskFragmentTest extends WindowTestsBase {
// Assert fixed orientation request is ignored for activity in ActivityEmbedding split.
activity0.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE);
- assertFalse(activity0.isLetterboxedForFixedOrientationAndAspectRatio());
+ assertFalse(activity0.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio());
assertEquals(SCREEN_ORIENTATION_UNSET, task.getOrientation());
activity1.setRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT);
- assertFalse(activity1.isLetterboxedForFixedOrientationAndAspectRatio());
+ assertFalse(activity1.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio());
assertEquals(SCREEN_ORIENTATION_UNSET, task.getOrientation());
// Also verify the behavior on device that ignore orientation request.
mDisplayContent.setIgnoreOrientationRequest(true);
task.onConfigurationChanged(task.getParent().getConfiguration());
- assertFalse(activity0.isLetterboxedForFixedOrientationAndAspectRatio());
- assertFalse(activity1.isLetterboxedForFixedOrientationAndAspectRatio());
+ assertFalse(activity0.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio());
+ assertFalse(activity1.mAppCompatController.getAppCompatAspectRatioPolicy()
+ .isLetterboxedForFixedOrientationAndAspectRatio());
assertEquals(SCREEN_ORIENTATION_UNSET, task.getOrientation());
tf0.setResumedActivity(activity0, "test");
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
index 4bc87b1237f0..76690ec1691f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -613,11 +613,12 @@ public class TaskTests extends WindowTestsBase {
final ActivityRecord root = task.getTopNonFinishingActivity();
spyOn(mWm.mLetterboxConfiguration);
spyOn(root);
- spyOn(root.mLetterboxUiController);
+ spyOn(root.mAppCompatController.getAppCompatAspectRatioOverrides());
doReturn(true).when(root).fillsParent();
- doReturn(true).when(root.mLetterboxUiController)
- .shouldEnableUserAspectRatioSettings();
+ doReturn(true).when(
+ root.mAppCompatController.getAppCompatAspectRatioOverrides())
+ .shouldEnableUserAspectRatioSettings();
doReturn(false).when(root).inSizeCompatMode();
doReturn(task).when(root).getOrganizedTask();
@@ -626,12 +627,13 @@ public class TaskTests extends WindowTestsBase {
.appCompatTaskInfo.topActivityEligibleForUserAspectRatioButton);
// When shouldApplyUserMinAspectRatioOverride is disable the button is not enabled
- doReturn(false).when(root.mLetterboxUiController)
- .shouldEnableUserAspectRatioSettings();
+ doReturn(false).when(
+ root.mAppCompatController.getAppCompatAspectRatioOverrides())
+ .shouldEnableUserAspectRatioSettings();
assertFalse(task.getTaskInfo()
.appCompatTaskInfo.topActivityEligibleForUserAspectRatioButton);
- doReturn(true).when(root.mLetterboxUiController)
- .shouldEnableUserAspectRatioSettings();
+ doReturn(true).when(root.mAppCompatController
+ .getAppCompatAspectRatioOverrides()).shouldEnableUserAspectRatioSettings();
// When in size compat mode the button is not enabled
doReturn(true).when(root).inSizeCompatMode();
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
index 00a8842c358e..38ad9a7e0dca 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -27,6 +27,7 @@ import android.os.PowerManager.GoToSleepReason;
import android.os.PowerManager.WakeReason;
import android.util.proto.ProtoOutputStream;
import android.view.KeyEvent;
+import android.view.KeyboardShortcutGroup;
import android.view.WindowManager;
import android.view.animation.Animation;
@@ -35,6 +36,7 @@ import com.android.internal.policy.IShortcutService;
import com.android.server.policy.WindowManagerPolicy;
import java.io.PrintWriter;
+import java.util.Collections;
class TestWindowManagerPolicy implements WindowManagerPolicy {
@@ -362,4 +364,9 @@ class TestWindowManagerPolicy implements WindowManagerPolicy {
public boolean isGlobalKey(int keyCode) {
return false;
}
+
+ @Override
+ public KeyboardShortcutGroup getApplicationLaunchKeyboardShortcuts(int deviceId) {
+ return new KeyboardShortcutGroup("", Collections.emptyList());
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
index a94b58690775..401964c2f597 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
@@ -22,6 +22,7 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.view.InsetsSource.FLAG_FORCE_CONSUMING;
import static android.view.WindowInsets.Type.systemOverlays;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
@@ -77,6 +78,7 @@ import android.os.Parcel;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ShellCallback;
+import android.platform.test.annotations.EnableFlags;
import android.platform.test.annotations.Presubmit;
import android.view.IRemoteAnimationFinishedCallback;
import android.view.IRemoteAnimationRunner;
@@ -91,6 +93,8 @@ import android.view.WindowManager;
import androidx.test.filters.SmallTest;
+import com.android.window.flags.Flags;
+
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -801,18 +805,11 @@ public class WindowContainerTests extends WindowTestsBase {
final TestWindowContainer root2 = builder.setLayer(0).build();
+ assertEquals("Roots have the same z-order", 0, root.compareTo(root2));
assertEquals(0, root.compareTo(root));
assertEquals(-1, child1.compareTo(child2));
assertEquals(1, child2.compareTo(child1));
- boolean inTheSameTree = true;
- try {
- root.compareTo(root2);
- } catch (IllegalArgumentException e) {
- inTheSameTree = false;
- }
- assertFalse(inTheSameTree);
-
assertEquals(-1, child1.compareTo(child11));
assertEquals(1, child21.compareTo(root));
assertEquals(1, child21.compareTo(child12));
@@ -960,6 +957,25 @@ public class WindowContainerTests extends WindowTestsBase {
assertTrue(child.handlesOrientationChangeFromDescendant(orientation));
}
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION)
+ public void testAddLocalInsets_addsFlagsFromProvider() {
+ final Task rootTask = createTask(mDisplayContent);
+ final Task task = createTaskInRootTask(rootTask, 0 /* userId */);
+
+ final Binder owner = new Binder();
+ Rect insetsRect = new Rect(0, 200, 1080, 700);
+ final int flags = FLAG_FORCE_CONSUMING;
+ final InsetsFrameProvider provider =
+ new InsetsFrameProvider(owner, 1, WindowInsets.Type.captionBar())
+ .setArbitraryRectangle(insetsRect)
+ .setFlags(flags);
+ task.addLocalInsetsFrameProvider(provider, owner);
+
+ final int sourceFlags = task.mLocalInsetsSources.get(provider.getId()).getFlags();
+ assertEquals(flags, sourceFlags);
+ }
+
private static void addLocalInsets(WindowContainer wc) {
final Binder owner = new Binder();
Rect genericOverlayInsetsRect1 = new Rect(0, 200, 1080, 700);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
index fcf7a3fe79c1..4958b904f326 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
@@ -1294,8 +1294,6 @@ public class WindowManagerServiceTests extends WindowTestsBase {
@Test
public void testRelayout_appWindowSendActivityWindowInfo() {
- mSetFlagsRule.enableFlags(Flags.FLAG_ACTIVITY_WINDOW_INFO_FLAG);
-
// Skip unnecessary operations of relayout.
spyOn(mWm.mWindowPlacerLocked);
doNothing().when(mWm.mWindowPlacerLocked).performSurfacePlacement(anyBoolean());
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
index d3504cc1bd28..fb81a52bce85 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
@@ -30,6 +30,7 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.content.res.Configuration.SCREEN_HEIGHT_DP_UNDEFINED;
import static android.content.res.Configuration.SCREEN_WIDTH_DP_UNDEFINED;
+import static android.view.InsetsSource.FLAG_FORCE_CONSUMING;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST;
@@ -75,10 +76,12 @@ import android.graphics.Rect;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
+import android.platform.test.annotations.EnableFlags;
import android.platform.test.annotations.Presubmit;
import android.util.ArrayMap;
import android.util.Rational;
import android.view.Display;
+import android.view.InsetsSource;
import android.view.SurfaceControl;
import android.view.WindowInsets;
import android.window.ITaskFragmentOrganizer;
@@ -904,7 +907,8 @@ public class WindowOrganizerTests extends WindowTestsBase {
0 /* index */,
WindowInsets.Type.systemOverlays(),
new Rect(0, 0, 1080, 200),
- null /* boundingRects */);
+ null /* boundingRects */,
+ 0 /* flags */);
mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct);
assertThat(navigationBarInsetsReceiverTask.mLocalInsetsSources
@@ -930,7 +934,8 @@ public class WindowOrganizerTests extends WindowTestsBase {
0 /* index */,
WindowInsets.Type.systemOverlays(),
new Rect(0, 0, 1080, 200),
- boundingRects);
+ boundingRects,
+ 0 /* flags */);
mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct);
assertArrayEquals(boundingRects, navigationBarInsetsReceiverTask.mLocalInsetsSources
@@ -938,6 +943,30 @@ public class WindowOrganizerTests extends WindowTestsBase {
}
@Test
+ @EnableFlags(Flags.FLAG_ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION)
+ public void testAddInsetsSource_withFlags() {
+ final Task rootTask = createTask(mDisplayContent);
+
+ final Task insetsReceiverTask = createTaskInRootTask(rootTask, 0);
+ insetsReceiverTask.getConfiguration().windowConfiguration
+ .setBounds(new Rect(0, 200, 1080, 700));
+
+ final @InsetsSource.Flags int flags = FLAG_FORCE_CONSUMING;
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ wct.addInsetsSource(
+ insetsReceiverTask.mRemoteToken.toWindowContainerToken(),
+ new Binder(),
+ 0 /* index */,
+ WindowInsets.Type.systemOverlays(),
+ new Rect(0, 0, 1080, 200),
+ null /* boundingRects */,
+ flags);
+ mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct);
+
+ assertEquals(flags, insetsReceiverTask.mLocalInsetsSources.valueAt(0).getFlags());
+ }
+
+ @Test
public void testRemoveInsetsSource() {
final Task rootTask = createTask(mDisplayContent);
@@ -952,7 +981,8 @@ public class WindowOrganizerTests extends WindowTestsBase {
0 /* index */,
WindowInsets.Type.systemOverlays(),
new Rect(0, 0, 1080, 200),
- null /* boundingRects */);
+ null /* boundingRects */,
+ 0 /* flags */);
mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct);
final WindowContainerTransaction wct2 = new WindowContainerTransaction();
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
index e6648dad4bbe..0cb22ad47355 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
@@ -18,6 +18,7 @@ package com.android.server.wm;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.content.pm.ActivityInfo.INSETS_DECOUPLED_CONFIGURATION_ENFORCED;
import static android.content.res.Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
@@ -86,6 +87,7 @@ public class WindowProcessControllerTests extends WindowTestsBase {
ApplicationInfo info = mock(ApplicationInfo.class);
info.packageName = "test.package.name";
+ doReturn(true).when(info).isChangeEnabled(INSETS_DECOUPLED_CONFIGURATION_ENFORCED);
mWpc = new WindowProcessController(
mAtm, info, null, 0, -1, null, mMockListener);
mWpc.setThread(mock(IApplicationThread.class));
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java b/services/tests/wmtests/src/com/android/server/wm/WindowTracingLegacyTest.java
index c1834037f791..48a8d5502c64 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTracingLegacyTest.java
@@ -63,7 +63,7 @@ import java.nio.charset.StandardCharsets;
*/
@SmallTest
@Presubmit
-public class WindowTracingTest {
+public class WindowTracingLegacyTest {
private static final byte[] MAGIC_HEADER = new byte[]{
0x9, 0x57, 0x49, 0x4e, 0x54, 0x52, 0x41, 0x43, 0x45,
@@ -88,7 +88,7 @@ public class WindowTracingTest {
mFile = testContext.getFileStreamPath("tracing_test.dat");
mFile.delete();
- mWindowTracing = new WindowTracing(mFile, mWmMock, mChoreographer,
+ mWindowTracing = new WindowTracingLegacy(mFile, mWmMock, mChoreographer,
new WindowManagerGlobalLock(), 1024);
}
diff --git a/telecomm/java/android/telecom/CallAudioState.java b/telecomm/java/android/telecom/CallAudioState.java
index 49e9232ad535..14c9ea51c618 100644
--- a/telecomm/java/android/telecom/CallAudioState.java
+++ b/telecomm/java/android/telecom/CallAudioState.java
@@ -159,7 +159,7 @@ public final class CallAudioState implements Parcelable {
@Override
public String toString() {
String bluetoothDeviceList = supportedBluetoothDevices.stream()
- .map(BluetoothDevice::getAddress).collect(Collectors.joining(", "));
+ .map(BluetoothDevice::toString).collect(Collectors.joining(", "));
return String.format(Locale.US,
"[AudioState isMuted: %b, route: %s, supportedRouteMask: %s, " +
diff --git a/telephony/java/android/telephony/satellite/SatelliteManager.java b/telephony/java/android/telephony/satellite/SatelliteManager.java
index b518c60d09fd..aebae4eec3f1 100644
--- a/telephony/java/android/telephony/satellite/SatelliteManager.java
+++ b/telephony/java/android/telephony/satellite/SatelliteManager.java
@@ -50,7 +50,6 @@ import java.lang.annotation.RetentionPolicy;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
@@ -2636,9 +2635,9 @@ public final class SatelliteManager {
if (resultCode == SATELLITE_RESULT_SUCCESS) {
if (resultData.containsKey(KEY_REQUEST_PROVISION_SUBSCRIBER_ID_TOKEN)) {
List<ProvisionSubscriberId> list =
- Collections.singletonList(resultData.getParcelable(
+ resultData.getParcelableArrayList(
KEY_REQUEST_PROVISION_SUBSCRIBER_ID_TOKEN,
- ProvisionSubscriberId.class));
+ ProvisionSubscriberId.class);
executor.execute(() -> Binder.withCleanCallingIdentity(() ->
callback.onResult(list)));
} else {
@@ -2692,13 +2691,13 @@ public final class SatelliteManager {
@Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
if (resultCode == SATELLITE_RESULT_SUCCESS) {
- if (resultData.containsKey(KEY_SATELLITE_PROVISIONED)) {
+ if (resultData.containsKey(KEY_IS_SATELLITE_PROVISIONED)) {
boolean isIsProvisioned =
- resultData.getBoolean(KEY_SATELLITE_PROVISIONED);
+ resultData.getBoolean(KEY_IS_SATELLITE_PROVISIONED);
executor.execute(() -> Binder.withCleanCallingIdentity(() ->
callback.onResult(isIsProvisioned)));
} else {
- loge("KEY_REQUEST_PROVISION_TOKENS does not exist.");
+ loge("KEY_IS_SATELLITE_PROVISIONED does not exist.");
executor.execute(() -> Binder.withCleanCallingIdentity(() ->
callback.onError(new SatelliteException(
SATELLITE_RESULT_REQUEST_FAILED))));
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 7be52ea62758..3dbda7ae10a3 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -3411,7 +3411,7 @@ interface ITelephony {
*/
@JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ "android.Manifest.permission.SATELLITE_COMMUNICATION)")
- void requestProvisionSubscriberIds(in ResultReceiver receiver);
+ void requestProvisionSubscriberIds(in ResultReceiver result);
/**
* Request to get provisioned status for given a satellite subscriber id.
diff --git a/tests/FlickerTests/IME/Android.bp b/tests/FlickerTests/IME/Android.bp
index ccc3683f0b93..78d93e1cb32a 100644
--- a/tests/FlickerTests/IME/Android.bp
+++ b/tests/FlickerTests/IME/Android.bp
@@ -34,6 +34,11 @@ filegroup {
srcs: ["src/**/Close*"],
}
+filegroup {
+ name: "FlickerTestsIme2-src",
+ srcs: ["src/**/ShowImeOnAppStart*"],
+}
+
android_test {
name: "FlickerTestsIme",
defaults: ["FlickerTestsDefault"],
@@ -77,9 +82,23 @@ android_test {
defaults: ["FlickerTestsDefault"],
manifest: "AndroidManifest.xml",
test_config_template: "AndroidTestTemplate.xml",
+ srcs: [":FlickerTestsIme2-src"],
+ static_libs: [
+ "FlickerTestsBase",
+ "FlickerTestsImeCommon",
+ ],
+ data: ["trace_config/*"],
+}
+
+android_test {
+ name: "FlickerTestsIme3",
+ defaults: ["FlickerTestsDefault"],
+ manifest: "AndroidManifest.xml",
+ test_config_template: "AndroidTestTemplate.xml",
srcs: ["src/**/*"],
exclude_srcs: [
":FlickerTestsIme1-src",
+ ":FlickerTestsIme2-src",
":FlickerTestsImeCommon-src",
],
static_libs: [
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/DesktopModeAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/DesktopModeAppHelper.kt
index 9a5e88becf1e..238f2afa7994 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/DesktopModeAppHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/DesktopModeAppHelper.kt
@@ -165,4 +165,37 @@ open class DesktopModeAppHelper(private val innerHelper: IStandardAppHelper) :
Corners.RIGHT_BOTTOM -> Pair(windowRect.right, windowRect.bottom)
}
}
+
+ /** Exit desktop mode by dragging the app handle to the top drag zone. */
+ fun exitDesktopWithDragToTopDragZone(
+ wmHelper: WindowManagerStateHelper,
+ device: UiDevice,
+ ) {
+ dragAppWindowToTopDragZone(wmHelper, device)
+ waitForTransitionToFullscreen(wmHelper)
+ }
+
+ private fun dragAppWindowToTopDragZone(wmHelper: WindowManagerStateHelper, device: UiDevice) {
+ val windowRect = wmHelper.getWindowRegion(innerHelper).bounds
+ val displayRect =
+ wmHelper.currentState.wmState.getDefaultDisplay()?.displayRect
+ ?: throw IllegalStateException("Default display is null")
+
+ val startX = windowRect.centerX()
+ val endX = displayRect.centerX()
+ val startY = windowRect.top
+ val endY = 0 // top of the screen
+
+ // drag the app window to top drag zone
+ device.drag(startX, startY, endX, endY, 100)
+ }
+
+ /** Wait for transition to full screen to finish. */
+ private fun waitForTransitionToFullscreen(wmHelper: WindowManagerStateHelper) {
+ wmHelper
+ .StateSyncBuilder()
+ .withFullScreenApp(innerHelper)
+ .withAppTransitionIdle()
+ .waitForAndVerify()
+ }
}
diff --git a/tests/Input/AndroidTest.xml b/tests/Input/AndroidTest.xml
index 8db37058af2b..4a99bd4f1801 100644
--- a/tests/Input/AndroidTest.xml
+++ b/tests/Input/AndroidTest.xml
@@ -31,7 +31,7 @@
<metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
<option name="pull-pattern-keys" value="input_.*" />
<!-- Pull files created by tests, like the output of screenshot tests -->
- <option name="directory-keys" value="/storage/emulated/0/InputTests" />
+ <option name="directory-keys" value="/sdcard/Download/InputTests" />
<option name="collect-on-run-ended-only" value="false" />
</metrics_collector>
</configuration>
diff --git a/tests/Input/src/com/android/test/input/PointerIconLoadingTest.kt b/tests/Input/src/com/android/test/input/PointerIconLoadingTest.kt
index e0f8c6d6ff4a..d0148fbbee3d 100644
--- a/tests/Input/src/com/android/test/input/PointerIconLoadingTest.kt
+++ b/tests/Input/src/com/android/test/input/PointerIconLoadingTest.kt
@@ -19,7 +19,6 @@ package com.android.test.input
import android.content.Context
import android.content.res.Configuration
import android.content.res.Resources
-import android.os.Environment
import android.view.ContextThemeWrapper
import android.view.PointerIcon
import android.view.flags.Flags.enableVectorCursorA11ySettings
@@ -158,8 +157,7 @@ class PointerIconLoadingTest {
const val SCREEN_WIDTH_DP = 480
const val SCREEN_HEIGHT_DP = 800
const val ASSETS_PATH = "tests/input/assets"
- val TEST_OUTPUT_PATH = Environment.getExternalStorageDirectory().absolutePath +
- "/InputTests/" +
- PointerIconLoadingTest::class.java.simpleName
+ val TEST_OUTPUT_PATH =
+ "/sdcard/Download/InputTests/" + PointerIconLoadingTest::class.java.simpleName
}
}
diff --git a/tests/Internal/src/com/android/internal/protolog/LegacyProtoLogViewerConfigReaderTest.java b/tests/Internal/src/com/android/internal/protolog/LegacyProtoLogViewerConfigReaderTest.java
new file mode 100644
index 000000000000..253965337824
--- /dev/null
+++ b/tests/Internal/src/com/android/internal/protolog/LegacyProtoLogViewerConfigReaderTest.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.protolog;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.util.zip.GZIPOutputStream;
+
+@SmallTest
+@Presubmit
+@RunWith(JUnit4.class)
+public class LegacyProtoLogViewerConfigReaderTest {
+ private static final String TEST_VIEWER_CONFIG = "{\n"
+ + " \"version\": \"1.0.0\",\n"
+ + " \"messages\": {\n"
+ + " \"70933285\": {\n"
+ + " \"message\": \"Test completed successfully: %b\",\n"
+ + " \"level\": \"ERROR\",\n"
+ + " \"group\": \"GENERIC_WM\"\n"
+ + " },\n"
+ + " \"1792430067\": {\n"
+ + " \"message\": \"Attempted to add window to a display that does not exist: %d."
+ + " Aborting.\",\n"
+ + " \"level\": \"WARN\",\n"
+ + " \"group\": \"GENERIC_WM\"\n"
+ + " },\n"
+ + " \"1352021864\": {\n"
+ + " \"message\": \"Test 2\",\n"
+ + " \"level\": \"WARN\",\n"
+ + " \"group\": \"GENERIC_WM\"\n"
+ + " },\n"
+ + " \"409412266\": {\n"
+ + " \"message\": \"Window %s is already added\",\n"
+ + " \"level\": \"WARN\",\n"
+ + " \"group\": \"GENERIC_WM\"\n"
+ + " }\n"
+ + " },\n"
+ + " \"groups\": {\n"
+ + " \"GENERIC_WM\": {\n"
+ + " \"tag\": \"WindowManager\"\n"
+ + " }\n"
+ + " }\n"
+ + "}\n";
+
+
+ private LegacyProtoLogViewerConfigReader
+ mConfig = new LegacyProtoLogViewerConfigReader();
+ private File mTestViewerConfig;
+
+ @Before
+ public void setUp() throws IOException {
+ mTestViewerConfig = File.createTempFile("testConfig", ".json.gz");
+ OutputStreamWriter writer = new OutputStreamWriter(
+ new GZIPOutputStream(new FileOutputStream(mTestViewerConfig)));
+ writer.write(TEST_VIEWER_CONFIG);
+ writer.close();
+ }
+
+ @After
+ public void tearDown() {
+ //noinspection ResultOfMethodCallIgnored
+ mTestViewerConfig.delete();
+ }
+
+ @Test
+ public void getViewerString_notLoaded() {
+ assertNull(mConfig.getViewerString(1));
+ }
+
+ @Test
+ public void loadViewerConfig() {
+ mConfig.loadViewerConfig(msg -> {}, mTestViewerConfig.getAbsolutePath());
+ assertEquals("Test completed successfully: %b", mConfig.getViewerString(70933285));
+ assertEquals("Test 2", mConfig.getViewerString(1352021864));
+ assertEquals("Window %s is already added", mConfig.getViewerString(409412266));
+ assertNull(mConfig.getViewerString(1));
+ }
+
+ @Test
+ public void loadViewerConfig_invalidFile() {
+ mConfig.loadViewerConfig(msg -> {}, "/tmp/unknown/file/does/not/exist");
+ // No exception is thrown.
+ assertNull(mConfig.getViewerString(1));
+ }
+}
diff --git a/tests/Internal/src/com/android/internal/protolog/ProtoLogViewerConfigReaderTest.java b/tests/Internal/src/com/android/internal/protolog/ProtoLogViewerConfigReaderTest.java
index dbd85d38b7f2..be0e8bc0fc07 100644
--- a/tests/Internal/src/com/android/internal/protolog/ProtoLogViewerConfigReaderTest.java
+++ b/tests/Internal/src/com/android/internal/protolog/ProtoLogViewerConfigReaderTest.java
@@ -20,75 +20,77 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import android.platform.test.annotations.Presubmit;
+import android.util.proto.ProtoInputStream;
-import androidx.test.filters.SmallTest;
-
-import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStreamWriter;
-import java.util.zip.GZIPOutputStream;
+import perfetto.protos.Protolog;
+import perfetto.protos.ProtologCommon;
-@SmallTest
@Presubmit
@RunWith(JUnit4.class)
public class ProtoLogViewerConfigReaderTest {
- private static final String TEST_VIEWER_CONFIG = "{\n"
- + " \"version\": \"1.0.0\",\n"
- + " \"messages\": {\n"
- + " \"70933285\": {\n"
- + " \"message\": \"Test completed successfully: %b\",\n"
- + " \"level\": \"ERROR\",\n"
- + " \"group\": \"GENERIC_WM\"\n"
- + " },\n"
- + " \"1792430067\": {\n"
- + " \"message\": \"Attempted to add window to a display that does not exist: %d."
- + " Aborting.\",\n"
- + " \"level\": \"WARN\",\n"
- + " \"group\": \"GENERIC_WM\"\n"
- + " },\n"
- + " \"1352021864\": {\n"
- + " \"message\": \"Test 2\",\n"
- + " \"level\": \"WARN\",\n"
- + " \"group\": \"GENERIC_WM\"\n"
- + " },\n"
- + " \"409412266\": {\n"
- + " \"message\": \"Window %s is already added\",\n"
- + " \"level\": \"WARN\",\n"
- + " \"group\": \"GENERIC_WM\"\n"
- + " }\n"
- + " },\n"
- + " \"groups\": {\n"
- + " \"GENERIC_WM\": {\n"
- + " \"tag\": \"WindowManager\"\n"
- + " }\n"
- + " }\n"
- + "}\n";
+ private static final String TEST_GROUP_NAME = "MY_TEST_GROUP";
+ private static final String TEST_GROUP_TAG = "TEST";
+ private static final String OTHER_TEST_GROUP_NAME = "MY_OTHER_TEST_GROUP";
+ private static final String OTHER_TEST_GROUP_TAG = "OTHER_TEST";
- private LegacyProtoLogViewerConfigReader
- mConfig = new LegacyProtoLogViewerConfigReader();
- private File mTestViewerConfig;
+ private static final byte[] TEST_VIEWER_CONFIG =
+ perfetto.protos.Protolog.ProtoLogViewerConfig.newBuilder()
+ .addGroups(
+ perfetto.protos.Protolog.ProtoLogViewerConfig.Group.newBuilder()
+ .setId(1)
+ .setName(TEST_GROUP_NAME)
+ .setTag(TEST_GROUP_TAG)
+ ).addGroups(
+ perfetto.protos.Protolog.ProtoLogViewerConfig.Group.newBuilder()
+ .setId(1)
+ .setName(OTHER_TEST_GROUP_NAME)
+ .setTag(OTHER_TEST_GROUP_TAG)
+ ).addMessages(
+ perfetto.protos.Protolog.ProtoLogViewerConfig.MessageData.newBuilder()
+ .setMessageId(1)
+ .setMessage("My Test Log Message 1 %b")
+ .setLevel(ProtologCommon.ProtoLogLevel.PROTOLOG_LEVEL_DEBUG)
+ .setGroupId(1)
+ ).addMessages(
+ perfetto.protos.Protolog.ProtoLogViewerConfig.MessageData.newBuilder()
+ .setMessageId(2)
+ .setMessage("My Test Log Message 2 %b")
+ .setLevel(ProtologCommon.ProtoLogLevel.PROTOLOG_LEVEL_VERBOSE)
+ .setGroupId(1)
+ ).addMessages(
+ perfetto.protos.Protolog.ProtoLogViewerConfig.MessageData.newBuilder()
+ .setMessageId(3)
+ .setMessage("My Test Log Message 3 %b")
+ .setLevel(ProtologCommon.ProtoLogLevel.PROTOLOG_LEVEL_WARN)
+ .setGroupId(1)
+ ).addMessages(
+ perfetto.protos.Protolog.ProtoLogViewerConfig.MessageData.newBuilder()
+ .setMessageId(4)
+ .setMessage("My Test Log Message 4 %b")
+ .setLevel(ProtologCommon.ProtoLogLevel.PROTOLOG_LEVEL_ERROR)
+ .setGroupId(2)
+ ).addMessages(
+ perfetto.protos.Protolog.ProtoLogViewerConfig.MessageData.newBuilder()
+ .setMessageId(5)
+ .setMessage("My Test Log Message 5 %b")
+ .setLevel(ProtologCommon.ProtoLogLevel.PROTOLOG_LEVEL_WTF)
+ .setGroupId(2)
+ ).build().toByteArray();
- @Before
- public void setUp() throws IOException {
- mTestViewerConfig = File.createTempFile("testConfig", ".json.gz");
- OutputStreamWriter writer = new OutputStreamWriter(
- new GZIPOutputStream(new FileOutputStream(mTestViewerConfig)));
- writer.write(TEST_VIEWER_CONFIG);
- writer.close();
- }
+ private final ViewerConfigInputStreamProvider mViewerConfigInputStreamProvider =
+ () -> new ProtoInputStream(TEST_VIEWER_CONFIG);
+
+ private ProtoLogViewerConfigReader mConfig;
- @After
- public void tearDown() {
- //noinspection ResultOfMethodCallIgnored
- mTestViewerConfig.delete();
+ @Before
+ public void before() {
+ mConfig = new ProtoLogViewerConfigReader(mViewerConfigInputStreamProvider);
}
@Test
@@ -98,17 +100,26 @@ public class ProtoLogViewerConfigReaderTest {
@Test
public void loadViewerConfig() {
- mConfig.loadViewerConfig(msg -> {}, mTestViewerConfig.getAbsolutePath());
- assertEquals("Test completed successfully: %b", mConfig.getViewerString(70933285));
- assertEquals("Test 2", mConfig.getViewerString(1352021864));
- assertEquals("Window %s is already added", mConfig.getViewerString(409412266));
- assertNull(mConfig.getViewerString(1));
+ mConfig.loadViewerConfig(new String[] { TEST_GROUP_NAME });
+ assertEquals("My Test Log Message 1 %b", mConfig.getViewerString(1));
+ assertEquals("My Test Log Message 2 %b", mConfig.getViewerString(2));
+ assertEquals("My Test Log Message 3 %b", mConfig.getViewerString(3));
+ assertNull(mConfig.getViewerString(4));
+ assertNull(mConfig.getViewerString(5));
}
@Test
- public void loadViewerConfig_invalidFile() {
- mConfig.loadViewerConfig(msg -> {}, "/tmp/unknown/file/does/not/exist");
- // No exception is thrown.
+ public void unloadViewerConfig() {
+ mConfig.loadViewerConfig(new String[] { TEST_GROUP_NAME, OTHER_TEST_GROUP_NAME });
+ mConfig.unloadViewerConfig(new String[] { TEST_GROUP_NAME });
assertNull(mConfig.getViewerString(1));
+ assertNull(mConfig.getViewerString(2));
+ assertNull(mConfig.getViewerString(3));
+ assertEquals("My Test Log Message 4 %b", mConfig.getViewerString(4));
+ assertEquals("My Test Log Message 5 %b", mConfig.getViewerString(5));
+
+ mConfig.unloadViewerConfig(new String[] { OTHER_TEST_GROUP_NAME });
+ assertNull(mConfig.getViewerString(4));
+ assertNull(mConfig.getViewerString(5));
}
}
diff --git a/tests/TrustTests/src/android/trust/test/UnlockAttemptTest.kt b/tests/TrustTests/src/android/trust/test/UnlockAttemptTest.kt
index 2c9361df63fd..f9e004bcd29e 100644
--- a/tests/TrustTests/src/android/trust/test/UnlockAttemptTest.kt
+++ b/tests/TrustTests/src/android/trust/test/UnlockAttemptTest.kt
@@ -17,6 +17,7 @@ package android.trust.test
import android.app.trust.TrustManager
import android.content.Context
+import android.security.Flags.shouldTrustManagerListenForPrimaryAuth
import android.trust.BaseTrustAgentService
import android.trust.TrustTestActivity
import android.trust.test.lib.LockStateTrackingRule
@@ -154,13 +155,17 @@ class UnlockAttemptTest {
private fun triggerSuccessfulUnlock() {
screenLockRule.successfulScreenLockAttempt()
- trustAgentRule.reportSuccessfulUnlock()
+ if (!shouldTrustManagerListenForPrimaryAuth()) {
+ trustAgentRule.reportSuccessfulUnlock()
+ }
await()
}
private fun triggerFailedUnlock() {
screenLockRule.failedScreenLockAttempt()
- trustAgentRule.reportFailedUnlock()
+ if (!shouldTrustManagerListenForPrimaryAuth()) {
+ trustAgentRule.reportFailedUnlock()
+ }
await()
}
diff --git a/tests/inputmethod/ConcurrentMultiSessionImeTest/src/com/android/server/inputmethod/multisessiontest/ConcurrentMultiUserTest.java b/tests/inputmethod/ConcurrentMultiSessionImeTest/src/com/android/server/inputmethod/multisessiontest/ConcurrentMultiUserTest.java
index 0db0d954d14d..f3851790688e 100644
--- a/tests/inputmethod/ConcurrentMultiSessionImeTest/src/com/android/server/inputmethod/multisessiontest/ConcurrentMultiUserTest.java
+++ b/tests/inputmethod/ConcurrentMultiSessionImeTest/src/com/android/server/inputmethod/multisessiontest/ConcurrentMultiUserTest.java
@@ -23,10 +23,15 @@ import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentat
import static com.android.compatibility.common.util.concurrentuser.ConcurrentUserActivityUtils.getResponderUserId;
import static com.android.compatibility.common.util.concurrentuser.ConcurrentUserActivityUtils.launchActivityAsUserSync;
import static com.android.compatibility.common.util.concurrentuser.ConcurrentUserActivityUtils.sendBundleAndWaitForReply;
+import static com.android.server.inputmethod.multisessiontest.TestRequestConstants.KEY_DISPLAY_ID;
+import static com.android.server.inputmethod.multisessiontest.TestRequestConstants.KEY_EDITTEXT_CENTER;
+import static com.android.server.inputmethod.multisessiontest.TestRequestConstants.KEY_IME_SHOWN;
import static com.android.server.inputmethod.multisessiontest.TestRequestConstants.KEY_REQUEST_CODE;
-import static com.android.server.inputmethod.multisessiontest.TestRequestConstants.KEY_RESULT_CODE;
-import static com.android.server.inputmethod.multisessiontest.TestRequestConstants.REPLY_IME_HIDDEN;
+import static com.android.server.inputmethod.multisessiontest.TestRequestConstants.REQUEST_DISPLAY_ID;
+import static com.android.server.inputmethod.multisessiontest.TestRequestConstants.REQUEST_EDITTEXT_POSITION;
+import static com.android.server.inputmethod.multisessiontest.TestRequestConstants.REQUEST_HIDE_IME;
import static com.android.server.inputmethod.multisessiontest.TestRequestConstants.REQUEST_IME_STATUS;
+import static com.android.server.inputmethod.multisessiontest.TestRequestConstants.REQUEST_SHOW_IME;
import static com.google.common.truth.Truth.assertWithMessage;
@@ -96,7 +101,7 @@ public final class ConcurrentMultiUserTest {
}
@Test
- public void driverShowImeNotAffectPassenger() {
+ public void driverShowImeNotAffectPassenger() throws Exception {
assertDriverImeHidden();
assertPassengerImeHidden();
@@ -105,6 +110,33 @@ public final class ConcurrentMultiUserTest {
}
@Test
+ public void passengerShowImeNotAffectDriver() throws Exception {
+ assertDriverImeHidden();
+ assertPassengerImeHidden();
+
+ showPassengerImeAndAssert();
+ assertDriverImeHidden();
+ }
+
+ @Test
+ public void driverHideImeNotAffectPassenger() throws Exception {
+ showDriverImeAndAssert();
+ showPassengerImeAndAssert();
+
+ hideDriverImeAndAssert();
+ assertPassengerImeShown();
+ }
+
+ @Test
+ public void passengerHideImeNotAffectDriver() throws Exception {
+ showDriverImeAndAssert();
+ showPassengerImeAndAssert();
+
+ hidePassengerImeAndAssert();
+ assertDriverImeShown();
+ }
+
+ @Test
public void imeListNotEmpty() {
List<InputMethodInfo> driverImeList = mInputMethodManager.getInputMethodList();
assertWithMessage("Driver IME list shouldn't be empty")
@@ -156,6 +188,11 @@ public final class ConcurrentMultiUserTest {
setImeForUser(passenger, driver);
}
+ private void assertDriverImeShown() {
+ assertWithMessage("Driver IME should be shown")
+ .that(mActivity.isMyImeVisible()).isTrue();
+ }
+
private void assertDriverImeHidden() {
assertWithMessage("Driver IME should be hidden")
.that(mActivity.isMyImeVisible()).isFalse();
@@ -167,13 +204,75 @@ public final class ConcurrentMultiUserTest {
Bundle receivedBundle = sendBundleAndWaitForReply(TEST_ACTIVITY.getPackageName(),
mPeerUserId, bundleToSend);
assertWithMessage("Passenger IME should be hidden")
- .that(receivedBundle.getInt(KEY_RESULT_CODE)).isEqualTo(REPLY_IME_HIDDEN);
+ .that(receivedBundle.getBoolean(KEY_IME_SHOWN, /* defaultValue= */ true)).isFalse();
+ }
+
+ private void assertPassengerImeShown() {
+ final Bundle bundleToSend = new Bundle();
+ bundleToSend.putInt(KEY_REQUEST_CODE, REQUEST_IME_STATUS);
+ Bundle receivedBundle = sendBundleAndWaitForReply(TEST_ACTIVITY.getPackageName(),
+ mPeerUserId, bundleToSend);
+ assertWithMessage("Passenger IME should be shown")
+ .that(receivedBundle.getBoolean(KEY_IME_SHOWN)).isTrue();
}
- private void showDriverImeAndAssert() {
+ private void showDriverImeAndAssert() throws Exception {
+ // WindowManagerInternal only allows the top focused display to show IME, so this method
+ // taps the driver display in case it is not the top focused display.
+ moveDriverDisplayToTop();
+
mActivity.showMyImeAndWait();
}
+ private void hideDriverImeAndAssert() {
+ mActivity.hideMyImeAndWait();
+ }
+
+ private void showPassengerImeAndAssert() throws Exception {
+ // WindowManagerInternal only allows the top focused display to show IME, so this method
+ // taps the passenger display in case it is not the top focused display.
+ movePassengerDisplayToTop();
+
+ Bundle bundleToSend = new Bundle();
+ bundleToSend.putInt(KEY_REQUEST_CODE, REQUEST_SHOW_IME);
+ Bundle receivedBundle = sendBundleAndWaitForReply(TEST_ACTIVITY.getPackageName(),
+ mPeerUserId, bundleToSend);
+
+ assertWithMessage("Passenger IME should be shown")
+ .that(receivedBundle.getBoolean(KEY_IME_SHOWN)).isTrue();
+ }
+
+ private void hidePassengerImeAndAssert() {
+ Bundle bundleToSend = new Bundle();
+ bundleToSend.putInt(KEY_REQUEST_CODE, REQUEST_HIDE_IME);
+ Bundle receivedBundle = sendBundleAndWaitForReply(TEST_ACTIVITY.getPackageName(),
+ mPeerUserId, bundleToSend);
+
+ assertWithMessage("Passenger IME should be hidden")
+ .that(receivedBundle.getBoolean(KEY_IME_SHOWN, /* defaultValue= */ true)).isFalse();
+ }
+
+ private void moveDriverDisplayToTop() throws Exception {
+ float[] driverEditTextCenter = mActivity.getEditTextCenter();
+ SystemUtil.runShellCommand(mUiAutomation, String.format("input tap %f %f",
+ driverEditTextCenter[0], driverEditTextCenter[1]));
+ }
+
+ private void movePassengerDisplayToTop() throws Exception {
+ final Bundle bundleToSend = new Bundle();
+ bundleToSend.putInt(KEY_REQUEST_CODE, REQUEST_EDITTEXT_POSITION);
+ Bundle receivedBundle = sendBundleAndWaitForReply(TEST_ACTIVITY.getPackageName(),
+ mPeerUserId, bundleToSend);
+ final float[] passengerEditTextCenter = receivedBundle.getFloatArray(KEY_EDITTEXT_CENTER);
+
+ bundleToSend.putInt(KEY_REQUEST_CODE, REQUEST_DISPLAY_ID);
+ receivedBundle = sendBundleAndWaitForReply(TEST_ACTIVITY.getPackageName(),
+ mPeerUserId, bundleToSend);
+ final int passengerDisplayId = receivedBundle.getInt(KEY_DISPLAY_ID);
+ SystemUtil.runShellCommand(mUiAutomation, String.format("input -d %d tap %f %f",
+ passengerDisplayId, passengerEditTextCenter[0], passengerEditTextCenter[1]));
+ }
+
/**
* Disables/enables IME for {@code user1}, then verifies that the IME settings for {@code user1}
* has changed as expected and {@code user2} stays the same.
diff --git a/tests/inputmethod/ConcurrentMultiSessionImeTest/src/com/android/server/inputmethod/multisessiontest/MainActivity.java b/tests/inputmethod/ConcurrentMultiSessionImeTest/src/com/android/server/inputmethod/multisessiontest/MainActivity.java
index 3c97b79b83c1..fa0aa19a8822 100644
--- a/tests/inputmethod/ConcurrentMultiSessionImeTest/src/com/android/server/inputmethod/multisessiontest/MainActivity.java
+++ b/tests/inputmethod/ConcurrentMultiSessionImeTest/src/com/android/server/inputmethod/multisessiontest/MainActivity.java
@@ -16,20 +16,25 @@
package com.android.server.inputmethod.multisessiontest;
+import static com.android.server.inputmethod.multisessiontest.TestRequestConstants.KEY_DISPLAY_ID;
+import static com.android.server.inputmethod.multisessiontest.TestRequestConstants.KEY_EDITTEXT_CENTER;
+import static com.android.server.inputmethod.multisessiontest.TestRequestConstants.KEY_IME_SHOWN;
import static com.android.server.inputmethod.multisessiontest.TestRequestConstants.KEY_REQUEST_CODE;
-import static com.android.server.inputmethod.multisessiontest.TestRequestConstants.KEY_RESULT_CODE;
-import static com.android.server.inputmethod.multisessiontest.TestRequestConstants.REPLY_IME_HIDDEN;
-import static com.android.server.inputmethod.multisessiontest.TestRequestConstants.REPLY_IME_SHOWN;
+import static com.android.server.inputmethod.multisessiontest.TestRequestConstants.REQUEST_DISPLAY_ID;
+import static com.android.server.inputmethod.multisessiontest.TestRequestConstants.REQUEST_EDITTEXT_POSITION;
+import static com.android.server.inputmethod.multisessiontest.TestRequestConstants.REQUEST_HIDE_IME;
import static com.android.server.inputmethod.multisessiontest.TestRequestConstants.REQUEST_IME_STATUS;
+import static com.android.server.inputmethod.multisessiontest.TestRequestConstants.REQUEST_SHOW_IME;
import android.app.Activity;
import android.os.Bundle;
import android.os.Process;
import android.util.Log;
-import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
+import androidx.annotation.WorkerThread;
import androidx.core.view.ViewCompat;
+import androidx.core.view.WindowCompat;
import androidx.core.view.WindowInsetsCompat;
import com.android.compatibility.common.util.PollingCheck;
@@ -43,7 +48,6 @@ public final class MainActivity extends ConcurrentUserActivityBase {
private static final long WAIT_IME_TIMEOUT_MS = 3000;
private EditText mEditor;
- private InputMethodManager mImm;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -52,19 +56,56 @@ public final class MainActivity extends ConcurrentUserActivityBase {
+ Process.myUserHandle().getIdentifier() + " on display "
+ getDisplay().getDisplayId());
setContentView(R.layout.main_activity);
- mImm = getSystemService(InputMethodManager.class);
mEditor = requireViewById(R.id.edit_text);
}
@Override
+ protected void onResume() {
+ super.onResume();
+ Log.v(TAG, "onResume");
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ Log.v(TAG, "onPause");
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ Log.v(TAG, "onResume");
+ }
+
+ @Override
+ public void onWindowFocusChanged(boolean hasFocus) {
+ super.onWindowFocusChanged(hasFocus);
+ Log.v(TAG, "onWindowFocusChanged " + hasFocus);
+ }
+
+ @Override
+ @WorkerThread
protected Bundle onBundleReceived(Bundle receivedBundle) {
final int requestCode = receivedBundle.getInt(KEY_REQUEST_CODE);
Log.v(TAG, "onBundleReceived() with request code:" + requestCode);
final Bundle replyBundle = new Bundle();
switch (requestCode) {
case REQUEST_IME_STATUS:
- replyBundle.putInt(KEY_RESULT_CODE,
- isMyImeVisible() ? REPLY_IME_SHOWN : REPLY_IME_HIDDEN);
+ replyBundle.putBoolean(KEY_IME_SHOWN, isMyImeVisible());
+ break;
+ case REQUEST_SHOW_IME:
+ showMyImeAndWait();
+ replyBundle.putBoolean(KEY_IME_SHOWN, isMyImeVisible());
+ break;
+ case REQUEST_HIDE_IME:
+ hideMyImeAndWait();
+ replyBundle.putBoolean(KEY_IME_SHOWN, isMyImeVisible());
+ break;
+ case REQUEST_EDITTEXT_POSITION:
+ replyBundle.putFloatArray(KEY_EDITTEXT_CENTER, getEditTextCenter());
+ break;
+ case REQUEST_DISPLAY_ID:
+ replyBundle.putInt(KEY_DISPLAY_ID, getDisplay().getDisplayId());
break;
default:
throw new RuntimeException("Received undefined request code:" + requestCode);
@@ -77,23 +118,41 @@ public final class MainActivity extends ConcurrentUserActivityBase {
return insets == null ? false : insets.isVisible(WindowInsetsCompat.Type.ime());
}
+ float[] getEditTextCenter() {
+ final float editTextCenterX = mEditor.getX() + 0.5f * mEditor.getWidth();
+ final float editTextCenterY = mEditor.getY() + 0.5f * mEditor.getHeight();
+ return new float[]{editTextCenterX, editTextCenterY};
+ }
+
+ @WorkerThread
void showMyImeAndWait() {
- Log.v(TAG, "showSoftInput");
runOnUiThread(() -> {
- // requestFocus() must run on UI thread.
+ // View#requestFocus() and WindowInsetsControllerCompat#show() must run on UI thread.
if (!mEditor.requestFocus()) {
Log.e(TAG, "Failed to focus on mEditor");
return;
}
- if (!mImm.showSoftInput(mEditor, /* flags= */ 0)) {
- Log.e(TAG, String.format("Failed to show my IME as user %d, "
- + "mEditor:focused=%b,hasWindowFocus=%b",
- Process.myUserHandle().getIdentifier(),
- mEditor.isFocused(), mEditor.hasWindowFocus()));
- }
+ // Compared to mImm.showSoftInput(), the call below is the recommended way to show the
+ // keyboard because it is guaranteed to be scheduled after the window is focused.
+ Log.v(TAG, "showSoftInput");
+ WindowCompat.getInsetsController(getWindow(), mEditor).show(
+ WindowInsetsCompat.Type.ime());
});
PollingCheck.waitFor(WAIT_IME_TIMEOUT_MS, () -> isMyImeVisible(),
- String.format("My IME (user %d) didn't show up",
+ String.format("%s: My IME (user %d) didn't show up", TAG,
+ Process.myUserHandle().getIdentifier()));
+ }
+
+ @WorkerThread
+ void hideMyImeAndWait() {
+ runOnUiThread(() -> {
+ Log.v(TAG, "hideSoftInput");
+ // WindowInsetsControllerCompat#hide() must run on UI thread.
+ WindowCompat.getInsetsController(getWindow(), mEditor)
+ .hide(WindowInsetsCompat.Type.ime());
+ });
+ PollingCheck.waitFor(WAIT_IME_TIMEOUT_MS, () -> !isMyImeVisible(),
+ String.format("%s: My IME (user %d) is still shown", TAG,
Process.myUserHandle().getIdentifier()));
}
}
diff --git a/tests/inputmethod/ConcurrentMultiSessionImeTest/src/com/android/server/inputmethod/multisessiontest/TestRequestConstants.java b/tests/inputmethod/ConcurrentMultiSessionImeTest/src/com/android/server/inputmethod/multisessiontest/TestRequestConstants.java
index 1501bfb69c92..68c9d5403c0b 100644
--- a/tests/inputmethod/ConcurrentMultiSessionImeTest/src/com/android/server/inputmethod/multisessiontest/TestRequestConstants.java
+++ b/tests/inputmethod/ConcurrentMultiSessionImeTest/src/com/android/server/inputmethod/multisessiontest/TestRequestConstants.java
@@ -21,9 +21,13 @@ final class TestRequestConstants {
}
public static final String KEY_REQUEST_CODE = "key_request_code";
- public static final String KEY_RESULT_CODE = "key_result_code";
+ public static final String KEY_EDITTEXT_CENTER = "key_edittext_center";
+ public static final String KEY_DISPLAY_ID = "key_display_id";
+ public static final String KEY_IME_SHOWN = "key_ime_shown";
public static final int REQUEST_IME_STATUS = 1;
- public static final int REPLY_IME_SHOWN = 2;
- public static final int REPLY_IME_HIDDEN = 3;
+ public static final int REQUEST_SHOW_IME = 2;
+ public static final int REQUEST_HIDE_IME = 3;
+ public static final int REQUEST_EDITTEXT_POSITION = 4;
+ public static final int REQUEST_DISPLAY_ID = 5;
}
diff --git a/tools/aapt2/cmd/Optimize.h b/tools/aapt2/cmd/Optimize.h
index ee53af107b17..012b0f230ca2 100644
--- a/tools/aapt2/cmd/Optimize.h
+++ b/tools/aapt2/cmd/Optimize.h
@@ -116,6 +116,10 @@ class OptimizeCommand : public Command {
"This decreases APK size at the cost of resource retrieval performance.\n"
"Applies sparse encoding to all resources regardless of minSdk.",
&options_.force_sparse_encoding);
+ AddOptionalSwitch(
+ "--enable-compact-entries",
+ "This decreases APK size by using compact resource entries for simple data types.",
+ &options_.table_flattener_options.use_compact_entries);
AddOptionalSwitch("--collapse-resource-names",
"Collapses resource names to a single value in the key string pool. Resources can \n"
"be exempted using the \"no_collapse\" directive in a file specified by "
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index 669cddb9af5a..cbf2c2fe8a9c 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -18,9 +18,9 @@
#include <unordered_set>
-#include "android-base/logging.h"
-
#include "ResourceUtils.h"
+#include "android-base/logging.h"
+#include "process/SymbolTable.h"
#include "trace/TraceBuffer.h"
#include "util/Util.h"
#include "xml/XmlActionExecutor.h"
@@ -172,6 +172,58 @@ static bool RequiredNameIsJavaClassName(xml::Element* el, android::SourcePathDia
return NameIsJavaClassName(el, attr, diag);
}
+static bool UpdateConfigChangesIfNeeded(xml::Element* el, IAaptContext* context) {
+ xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "configChanges");
+ if (attr == nullptr) {
+ return true;
+ }
+
+ if (attr->value != "allKnown" && attr->value.find("allKnown") != std::string::npos) {
+ context->GetDiagnostics()->Error(
+ android::DiagMessage(el->line_number)
+ << "If you want to declare 'allKnown' in attribute 'android:configChanges' in <" << el->name
+ << ">, " << attr->value << " is not allowed', allKnown has to be used "
+ << "by itself, for example: 'android:configChanges=allKnown', it cannot be combined with "
+ << "the other flags");
+ return false;
+ }
+
+ if (attr->value == "allKnown") {
+ SymbolTable* symbol_table = context->GetExternalSymbols();
+ const SymbolTable::Symbol* symbol =
+ symbol_table->FindByName(ResourceName("android", ResourceType::kAttr, "configChanges"));
+
+ if (symbol == nullptr) {
+ context->GetDiagnostics()->Error(
+ android::DiagMessage(el->line_number)
+ << "Cannot find symbol for android:configChanges with min sdk: "
+ << context->GetMinSdkVersion());
+ }
+
+ std::stringstream new_value;
+
+ const auto& symbols = symbol->attribute->symbols;
+ for (auto it = symbols.begin(); it != symbols.end(); ++it) {
+ // Skip 'resourcesUnused' which is the flag to fully disable activity restart specifically
+ // for games.
+ if (it->symbol.name.value().entry == "resourcesUnused") {
+ continue;
+ }
+ if (it != symbols.begin()) {
+ new_value << "|";
+ }
+ new_value << it->symbol.name.value().entry;
+ }
+ const auto& old_value = attr->value;
+ auto new_value_str = new_value.str();
+ context->GetDiagnostics()->Note(android::DiagMessage(el->line_number)
+ << "Updating value of 'android:configChanges' from "
+ << old_value << " to " << new_value_str);
+ attr->value = std::move(new_value_str);
+ }
+ return true;
+}
+
static bool RequiredNameIsJavaPackage(xml::Element* el, android::SourcePathDiagnostics* diag) {
xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "name");
if (attr == nullptr) {
@@ -382,8 +434,9 @@ static void EnsureNamespaceIsDeclared(const std::string& prefix, const std::stri
}
}
-bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor, android::IDiagnostics* diag) {
+bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor, IAaptContext* context) {
// First verify some options.
+ android::IDiagnostics* diag = context->GetDiagnostics();
if (options_.rename_manifest_package) {
if (!util::IsJavaPackageName(options_.rename_manifest_package.value())) {
diag->Error(android::DiagMessage() << "invalid manifest package override '"
@@ -432,6 +485,8 @@ bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor, android::IDiagn
// Common component actions.
xml::XmlNodeAction component_action;
component_action.Action(RequiredNameIsJavaClassName);
+ component_action.Action(
+ [context](xml::Element* el) -> bool { return UpdateConfigChangesIfNeeded(el, context); });
component_action["intent-filter"] = intent_filter_action;
component_action["preferred"] = intent_filter_action;
component_action["meta-data"] = meta_data_action;
@@ -778,7 +833,7 @@ bool ManifestFixer::Consume(IAaptContext* context, xml::XmlResource* doc) {
}
xml::XmlActionExecutor executor;
- if (!BuildRules(&executor, context->GetDiagnostics())) {
+ if (!BuildRules(&executor, context)) {
return false;
}
diff --git a/tools/aapt2/link/ManifestFixer.h b/tools/aapt2/link/ManifestFixer.h
index df0ece6fe24a..748a82858175 100644
--- a/tools/aapt2/link/ManifestFixer.h
+++ b/tools/aapt2/link/ManifestFixer.h
@@ -110,7 +110,7 @@ class ManifestFixer : public IXmlResourceConsumer {
private:
DISALLOW_COPY_AND_ASSIGN(ManifestFixer);
- bool BuildRules(xml::XmlActionExecutor* executor, android::IDiagnostics* diag);
+ bool BuildRules(xml::XmlActionExecutor* executor, IAaptContext* context);
ManifestFixerOptions options_;
};
diff --git a/tools/aapt2/link/ManifestFixer_test.cpp b/tools/aapt2/link/ManifestFixer_test.cpp
index 3cfdf7832801..50086273a819 100644
--- a/tools/aapt2/link/ManifestFixer_test.cpp
+++ b/tools/aapt2/link/ManifestFixer_test.cpp
@@ -37,27 +37,30 @@ struct ManifestFixerTest : public ::testing::Test {
.SetCompilationPackage("android")
.SetPackageId(0x01)
.SetNameManglerPolicy(NameManglerPolicy{"android"})
- .AddSymbolSource(
- test::StaticSymbolSourceBuilder()
- .AddSymbol(
- "android:attr/package", ResourceId(0x01010000),
- test::AttributeBuilder()
- .SetTypeMask(android::ResTable_map::TYPE_STRING)
- .Build())
- .AddSymbol(
- "android:attr/minSdkVersion", ResourceId(0x01010001),
- test::AttributeBuilder()
- .SetTypeMask(android::ResTable_map::TYPE_STRING |
- android::ResTable_map::TYPE_INTEGER)
- .Build())
- .AddSymbol(
- "android:attr/targetSdkVersion", ResourceId(0x01010002),
- test::AttributeBuilder()
- .SetTypeMask(android::ResTable_map::TYPE_STRING |
- android::ResTable_map::TYPE_INTEGER)
- .Build())
- .AddSymbol("android:string/str", ResourceId(0x01060000))
- .Build())
+ .AddSymbolSource(test::StaticSymbolSourceBuilder()
+ .AddSymbol("android:attr/package", ResourceId(0x01010000),
+ test::AttributeBuilder()
+ .SetTypeMask(android::ResTable_map::TYPE_STRING)
+ .Build())
+ .AddSymbol("android:attr/minSdkVersion", ResourceId(0x01010001),
+ test::AttributeBuilder()
+ .SetTypeMask(android::ResTable_map::TYPE_STRING |
+ android::ResTable_map::TYPE_INTEGER)
+ .Build())
+ .AddSymbol("android:attr/targetSdkVersion", ResourceId(0x01010002),
+ test::AttributeBuilder()
+ .SetTypeMask(android::ResTable_map::TYPE_STRING |
+ android::ResTable_map::TYPE_INTEGER)
+ .Build())
+ .AddSymbol("android:string/str", ResourceId(0x01060000))
+ .AddSymbol("android:attr/configChanges", ResourceId(0x01010003),
+ test::AttributeBuilder()
+ .AddItem("testConfigChange1", 1)
+ .AddItem("testConfigChange2", 2)
+ .AddItem("resourcesUnused", 4)
+ .SetTypeMask(android::ResTable_map::TYPE_STRING)
+ .Build())
+ .Build())
.Build();
}
@@ -1591,4 +1594,72 @@ TEST_F(ManifestFixerTest, IntentFilterPathMustStartWithLeadingSlashOnDeepLinks)
</manifest>)";
EXPECT_THAT(Verify(input), NotNull());
}
+
+TEST_F(ManifestFixerTest, AllKnownNotDeclaredProperly) {
+ std::string input = R"(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android">
+ <application>
+ <activity android:name=".MainActivity"
+ android:configChanges="allKnown|testConfigChange1">
+ </activity>
+ </application>
+ </manifest>)";
+ auto doc = Verify(input);
+ EXPECT_THAT(doc, IsNull());
+}
+
+TEST_F(ManifestFixerTest, ModifyAttributeValueForAllKnown) {
+ std::string input = R"(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android">
+ <application>
+ <activity android:name=".MainActivity"
+ android:configChanges="allKnown">
+ </activity>
+ </application>
+ </manifest>)";
+ auto doc = Verify(input);
+ EXPECT_THAT(doc, NotNull());
+
+ xml::Element* el;
+ xml::Attribute* attr;
+
+ el = doc->root.get();
+ ASSERT_THAT(el, NotNull());
+ el = el->FindChild({}, "application");
+ ASSERT_THAT(el, NotNull());
+ el = el->FindChild({}, "activity");
+ ASSERT_THAT(el, NotNull());
+
+ attr = el->FindAttribute(xml::kSchemaAndroid, "configChanges");
+ ASSERT_THAT(attr->value, "testConfigChange1|testConfigChange2");
+}
+
+TEST_F(ManifestFixerTest, DoNothingForOtherConfigChanges) {
+ std::string input = R"(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android">
+ <application>
+ <activity android:name=".MainActivity"
+ android:configChanges="testConfigChange2">
+ </activity>
+ </application>
+ </manifest>)";
+ auto doc = Verify(input);
+ EXPECT_THAT(doc, NotNull());
+
+ xml::Element* el;
+ xml::Attribute* attr;
+
+ el = doc->root.get();
+ ASSERT_THAT(el, NotNull());
+ el = el->FindChild({}, "application");
+ ASSERT_THAT(el, NotNull());
+ el = el->FindChild({}, "activity");
+ ASSERT_THAT(el, NotNull());
+
+ attr = el->FindAttribute(xml::kSchemaAndroid, "configChanges");
+ ASSERT_THAT(attr->value, "testConfigChange2");
+}
} // namespace aapt
diff --git a/tools/aapt2/util/Files.cpp b/tools/aapt2/util/Files.cpp
index 02e4beaed949..8ae55b8868c3 100644
--- a/tools/aapt2/util/Files.cpp
+++ b/tools/aapt2/util/Files.cpp
@@ -189,7 +189,7 @@ void AppendPath(std::string* base, StringPiece part) {
base->append(part.data(), part.size());
}
-std::string BuildPath(std::vector<const StringPiece>&& args) {
+std::string BuildPath(const std::vector<StringPiece>& args) {
if (args.empty()) {
return "";
}
diff --git a/tools/aapt2/util/Files.h b/tools/aapt2/util/Files.h
index 42eeaf2d2e2a..c1a42446ec3b 100644
--- a/tools/aapt2/util/Files.h
+++ b/tools/aapt2/util/Files.h
@@ -60,7 +60,7 @@ FileType GetFileType(const std::string& path);
void AppendPath(std::string* base, android::StringPiece part);
// Concatenates the list of paths and separates each part with the directory separator.
-std::string BuildPath(std::vector<const android::StringPiece>&& args);
+std::string BuildPath(const std::vector<android::StringPiece>& args);
// Makes all the directories in `path`. The last element in the path is interpreted as a directory.
bool mkdirs(const std::string& path);
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/AslConverter.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/AslConverter.java
index 191f38d3df80..718d8987c13b 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/AslConverter.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/AslConverter.java
@@ -62,13 +62,11 @@ public class AslConverter {
XmlUtils.getSingleChildElement(
document, XmlUtils.HR_TAG_APP_METADATA_BUNDLES, true);
- return new AndroidSafetyLabelFactory()
- .createFromHrElements(XmlUtils.listOf(appMetadataBundles));
+ return new AndroidSafetyLabelFactory().createFromHrElement(appMetadataBundles);
case ON_DEVICE:
Element bundleEle =
XmlUtils.getSingleChildElement(document, XmlUtils.OD_TAG_BUNDLE, true);
- return new AndroidSafetyLabelFactory()
- .createFromOdElements(XmlUtils.listOf(bundleEle));
+ return new AndroidSafetyLabelFactory().createFromOdElement(bundleEle);
default:
throw new IllegalStateException("Unrecognized input format.");
}
@@ -91,14 +89,10 @@ public class AslConverter {
switch (format) {
case HUMAN_READABLE:
- for (var child : asl.toHrDomElements(document)) {
- document.appendChild(child);
- }
+ document.appendChild(asl.toHrDomElement(document));
break;
case ON_DEVICE:
- for (var child : asl.toOdDomElements(document)) {
- document.appendChild(child);
- }
+ document.appendChild(asl.toOdDomElement(document));
break;
default:
throw new IllegalStateException("Unrecognized input format.");
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AndroidSafetyLabel.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AndroidSafetyLabel.java
index 72140a17297c..8b2fd93df889 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AndroidSafetyLabel.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AndroidSafetyLabel.java
@@ -21,8 +21,6 @@ import com.android.asllib.util.XmlUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
-import java.util.List;
-
public class AndroidSafetyLabel implements AslMarshallable {
private final Long mVersion;
@@ -46,36 +44,34 @@ public class AndroidSafetyLabel implements AslMarshallable {
}
/** Creates an on-device DOM element from an {@link AndroidSafetyLabel} */
- @Override
- public List<Element> toOdDomElements(Document doc) {
+ public Element toOdDomElement(Document doc) {
Element aslEle = doc.createElement(XmlUtils.OD_TAG_BUNDLE);
aslEle.appendChild(XmlUtils.createOdLongEle(doc, XmlUtils.OD_NAME_VERSION, mVersion));
if (mSafetyLabels != null) {
- XmlUtils.appendChildren(aslEle, mSafetyLabels.toOdDomElements(doc));
+ aslEle.appendChild(mSafetyLabels.toOdDomElement(doc));
}
if (mSystemAppSafetyLabel != null) {
- XmlUtils.appendChildren(aslEle, mSystemAppSafetyLabel.toOdDomElements(doc));
+ aslEle.appendChild(mSystemAppSafetyLabel.toOdDomElement(doc));
}
if (mTransparencyInfo != null) {
- XmlUtils.appendChildren(aslEle, mTransparencyInfo.toOdDomElements(doc));
+ aslEle.appendChild(mTransparencyInfo.toOdDomElement(doc));
}
- return XmlUtils.listOf(aslEle);
+ return aslEle;
}
/** Creates the human-readable DOM elements from the AslMarshallable Java Object. */
- @Override
- public List<Element> toHrDomElements(Document doc) {
+ public Element toHrDomElement(Document doc) {
Element aslEle = doc.createElement(XmlUtils.HR_TAG_APP_METADATA_BUNDLES);
aslEle.setAttribute(XmlUtils.HR_ATTR_VERSION, String.valueOf(mVersion));
if (mSafetyLabels != null) {
- XmlUtils.appendChildren(aslEle, mSafetyLabels.toHrDomElements(doc));
+ aslEle.appendChild(mSafetyLabels.toHrDomElement(doc));
}
if (mSystemAppSafetyLabel != null) {
- XmlUtils.appendChildren(aslEle, mSystemAppSafetyLabel.toHrDomElements(doc));
+ aslEle.appendChild(mSystemAppSafetyLabel.toHrDomElement(doc));
}
if (mTransparencyInfo != null) {
- XmlUtils.appendChildren(aslEle, mTransparencyInfo.toHrDomElements(doc));
+ aslEle.appendChild(mTransparencyInfo.toHrDomElement(doc));
}
- return XmlUtils.listOf(aslEle);
+ return aslEle;
}
}
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AndroidSafetyLabelFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AndroidSafetyLabelFactory.java
index c53cbbf99a46..b9eb2a35e63b 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AndroidSafetyLabelFactory.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AndroidSafetyLabelFactory.java
@@ -21,65 +21,117 @@ import com.android.asllib.util.XmlUtils;
import org.w3c.dom.Element;
-import java.util.List;
+import java.util.Map;
+import java.util.Set;
public class AndroidSafetyLabelFactory implements AslMarshallableFactory<AndroidSafetyLabel> {
+ private final Map<Long, Set<String>> mRecognizedHrAttrs =
+ Map.ofEntries(Map.entry(1L, Set.of(XmlUtils.HR_ATTR_VERSION)));
+ private final Map<Long, Set<String>> mRequiredHrAttrs =
+ Map.ofEntries(Map.entry(1L, Set.of(XmlUtils.HR_ATTR_VERSION)));
+ private final Map<Long, Set<String>> mRecognizedHrEles =
+ Map.ofEntries(
+ Map.entry(
+ 1L,
+ Set.of(
+ XmlUtils.HR_TAG_SYSTEM_APP_SAFETY_LABEL,
+ XmlUtils.HR_TAG_SAFETY_LABELS,
+ XmlUtils.HR_TAG_TRANSPARENCY_INFO)));
+ private final Map<Long, Set<String>> mRequiredHrEles =
+ Map.ofEntries(
+ Map.entry(1L, Set.of()),
+ Map.entry(
+ 2L,
+ Set.of(
+ XmlUtils.HR_TAG_SYSTEM_APP_SAFETY_LABEL,
+ XmlUtils.HR_TAG_TRANSPARENCY_INFO)));
+ private final Map<Long, Set<String>> mRecognizedOdEleNames =
+ Map.ofEntries(
+ Map.entry(
+ 1L,
+ Set.of(
+ XmlUtils.OD_NAME_VERSION,
+ XmlUtils.OD_NAME_SAFETY_LABELS,
+ XmlUtils.OD_NAME_SYSTEM_APP_SAFETY_LABEL,
+ XmlUtils.OD_NAME_TRANSPARENCY_INFO)));
+ private final Map<Long, Set<String>> mRequiredOdEleNames =
+ Map.ofEntries(
+ Map.entry(1L, Set.of(XmlUtils.OD_NAME_VERSION)),
+ Map.entry(
+ 2L,
+ Set.of(
+ XmlUtils.OD_NAME_VERSION,
+ XmlUtils.OD_NAME_SYSTEM_APP_SAFETY_LABEL,
+ XmlUtils.OD_NAME_TRANSPARENCY_INFO)));
/** Creates an {@link AndroidSafetyLabel} from human-readable DOM element */
- @Override
- public AndroidSafetyLabel createFromHrElements(List<Element> appMetadataBundles)
+ public AndroidSafetyLabel createFromHrElement(Element appMetadataBundlesEle)
throws MalformedXmlException {
- Element appMetadataBundlesEle = XmlUtils.getSingleElement(appMetadataBundles);
long version = XmlUtils.tryGetVersion(appMetadataBundlesEle);
+ XmlUtils.throwIfExtraneousAttributes(
+ appMetadataBundlesEle, XmlUtils.getMostRecentVersion(mRecognizedHrAttrs, version));
+ XmlUtils.throwIfExtraneousChildrenHr(
+ appMetadataBundlesEle, XmlUtils.getMostRecentVersion(mRecognizedHrEles, version));
Element safetyLabelsEle =
XmlUtils.getSingleChildElement(
- appMetadataBundlesEle, XmlUtils.HR_TAG_SAFETY_LABELS, false);
+ appMetadataBundlesEle,
+ XmlUtils.HR_TAG_SAFETY_LABELS,
+ XmlUtils.getMostRecentVersion(mRequiredHrEles, version));
SafetyLabels safetyLabels =
- new SafetyLabelsFactory().createFromHrElements(XmlUtils.listOf(safetyLabelsEle));
+ new SafetyLabelsFactory().createFromHrElement(safetyLabelsEle, version);
Element systemAppSafetyLabelEle =
XmlUtils.getSingleChildElement(
- appMetadataBundlesEle, XmlUtils.HR_TAG_SYSTEM_APP_SAFETY_LABEL, false);
+ appMetadataBundlesEle,
+ XmlUtils.HR_TAG_SYSTEM_APP_SAFETY_LABEL,
+ XmlUtils.getMostRecentVersion(mRequiredHrEles, version));
SystemAppSafetyLabel systemAppSafetyLabel =
new SystemAppSafetyLabelFactory()
- .createFromHrElements(XmlUtils.listOf(systemAppSafetyLabelEle));
+ .createFromHrElement(systemAppSafetyLabelEle, version);
Element transparencyInfoEle =
XmlUtils.getSingleChildElement(
- appMetadataBundlesEle, XmlUtils.HR_TAG_TRANSPARENCY_INFO, false);
+ appMetadataBundlesEle,
+ XmlUtils.HR_TAG_TRANSPARENCY_INFO,
+ XmlUtils.getMostRecentVersion(mRequiredHrEles, version));
TransparencyInfo transparencyInfo =
- new TransparencyInfoFactory()
- .createFromHrElements(XmlUtils.listOf(transparencyInfoEle));
+ new TransparencyInfoFactory().createFromHrElement(transparencyInfoEle, version);
return new AndroidSafetyLabel(
version, systemAppSafetyLabel, safetyLabels, transparencyInfo);
}
/** Creates an {@link AndroidSafetyLabel} from on-device DOM elements */
- @Override
- public AndroidSafetyLabel createFromOdElements(List<Element> elements)
- throws MalformedXmlException {
- Element bundleEle = XmlUtils.getSingleElement(elements);
+ public AndroidSafetyLabel createFromOdElement(Element bundleEle) throws MalformedXmlException {
Long version = XmlUtils.getOdLongEle(bundleEle, XmlUtils.OD_NAME_VERSION, true);
+ XmlUtils.throwIfExtraneousChildrenOd(
+ bundleEle, XmlUtils.getMostRecentVersion(mRecognizedOdEleNames, version));
Element safetyLabelsEle =
- XmlUtils.getOdPbundleWithName(bundleEle, XmlUtils.OD_NAME_SAFETY_LABELS, false);
+ XmlUtils.getOdPbundleWithName(
+ bundleEle,
+ XmlUtils.OD_NAME_SAFETY_LABELS,
+ XmlUtils.getMostRecentVersion(mRequiredOdEleNames, version));
SafetyLabels safetyLabels =
- new SafetyLabelsFactory().createFromOdElements(XmlUtils.listOf(safetyLabelsEle));
+ new SafetyLabelsFactory().createFromOdElement(safetyLabelsEle, version);
Element systemAppSafetyLabelEle =
XmlUtils.getOdPbundleWithName(
- bundleEle, XmlUtils.OD_NAME_SYSTEM_APP_SAFETY_LABEL, false);
+ bundleEle,
+ XmlUtils.OD_NAME_SYSTEM_APP_SAFETY_LABEL,
+ XmlUtils.getMostRecentVersion(mRequiredOdEleNames, version));
SystemAppSafetyLabel systemAppSafetyLabel =
new SystemAppSafetyLabelFactory()
- .createFromOdElements(XmlUtils.listOf(systemAppSafetyLabelEle));
+ .createFromOdElement(systemAppSafetyLabelEle, version);
Element transparencyInfoEle =
- XmlUtils.getOdPbundleWithName(bundleEle, XmlUtils.OD_NAME_TRANSPARENCY_INFO, false);
+ XmlUtils.getOdPbundleWithName(
+ bundleEle,
+ XmlUtils.OD_NAME_TRANSPARENCY_INFO,
+ XmlUtils.getMostRecentVersion(mRequiredOdEleNames, version));
TransparencyInfo transparencyInfo =
- new TransparencyInfoFactory()
- .createFromOdElements(XmlUtils.listOf(transparencyInfoEle));
+ new TransparencyInfoFactory().createFromOdElement(transparencyInfoEle, version);
return new AndroidSafetyLabel(
version, systemAppSafetyLabel, safetyLabels, transparencyInfo);
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AppInfo.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AppInfo.java
index f39722589a96..d2557aec5f82 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AppInfo.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AppInfo.java
@@ -25,36 +25,107 @@ import java.util.List;
/** AppInfo representation */
public class AppInfo implements AslMarshallable {
- private final Boolean mApsCompliant;
+ private final String mTitle;
+ private final String mDescription;
+ private final Boolean mContainsAds;
+ private final Boolean mObeyAps;
+ private final Boolean mAdsFingerprinting;
+ private final Boolean mSecurityFingerprinting;
private final String mPrivacyPolicy;
+ private final List<String> mSecurityEndpoints;
private final List<String> mFirstPartyEndpoints;
private final List<String> mServiceProviderEndpoints;
+ private final String mCategory;
+ private final String mEmail;
+ private final String mWebsite;
+
+ private final Boolean mApsCompliant;
+ private final String mDeveloperId;
+ private final String mApplicationId;
+
+ // private final String mPrivacyPolicy;
+ // private final List<String> mFirstPartyEndpoints;
+ // private final List<String> mServiceProviderEndpoints;
public AppInfo(
- Boolean apsCompliant,
+ String title,
+ String description,
+ Boolean containsAds,
+ Boolean obeyAps,
+ Boolean adsFingerprinting,
+ Boolean securityFingerprinting,
String privacyPolicy,
+ List<String> securityEndpoints,
List<String> firstPartyEndpoints,
- List<String> serviceProviderEndpoints) {
- this.mApsCompliant = apsCompliant;
+ List<String> serviceProviderEndpoints,
+ String category,
+ String email,
+ String website,
+ Boolean apsCompliant,
+ String developerId,
+ String applicationId) {
+ this.mTitle = title;
+ this.mDescription = description;
+ this.mContainsAds = containsAds;
+ this.mObeyAps = obeyAps;
+ this.mAdsFingerprinting = adsFingerprinting;
+ this.mSecurityFingerprinting = securityFingerprinting;
this.mPrivacyPolicy = privacyPolicy;
+ this.mSecurityEndpoints = securityEndpoints;
this.mFirstPartyEndpoints = firstPartyEndpoints;
this.mServiceProviderEndpoints = serviceProviderEndpoints;
+ this.mCategory = category;
+ this.mEmail = email;
+ this.mWebsite = website;
+ this.mApsCompliant = apsCompliant;
+ this.mDeveloperId = developerId;
+ this.mApplicationId = applicationId;
}
/** Creates an on-device DOM element from the {@link SafetyLabels}. */
- @Override
- public List<Element> toOdDomElements(Document doc) {
+ public Element toOdDomElement(Document doc) {
Element appInfoEle = XmlUtils.createPbundleEleWithName(doc, XmlUtils.OD_NAME_APP_INFO);
- if (this.mApsCompliant != null) {
+
+ if (this.mTitle != null) {
+ appInfoEle.appendChild(XmlUtils.createOdStringEle(doc, XmlUtils.OD_NAME_TITLE, mTitle));
+ }
+ if (this.mDescription != null) {
+ appInfoEle.appendChild(
+ XmlUtils.createOdStringEle(doc, XmlUtils.OD_NAME_DESCRIPTION, mDescription));
+ }
+ if (this.mContainsAds != null) {
+ appInfoEle.appendChild(
+ XmlUtils.createOdBooleanEle(doc, XmlUtils.OD_NAME_CONTAINS_ADS, mContainsAds));
+ }
+ if (this.mObeyAps != null) {
+ appInfoEle.appendChild(
+ XmlUtils.createOdBooleanEle(doc, XmlUtils.OD_NAME_OBEY_APS, mObeyAps));
+ }
+ if (this.mAdsFingerprinting != null) {
appInfoEle.appendChild(
XmlUtils.createOdBooleanEle(
- doc, XmlUtils.OD_NAME_APS_COMPLIANT, mApsCompliant));
+ doc, XmlUtils.OD_NAME_ADS_FINGERPRINTING, mAdsFingerprinting));
+ }
+ if (this.mSecurityFingerprinting != null) {
+ appInfoEle.appendChild(
+ XmlUtils.createOdBooleanEle(
+ doc,
+ XmlUtils.OD_NAME_SECURITY_FINGERPRINTING,
+ mSecurityFingerprinting));
}
if (this.mPrivacyPolicy != null) {
appInfoEle.appendChild(
XmlUtils.createOdStringEle(
doc, XmlUtils.OD_NAME_PRIVACY_POLICY, mPrivacyPolicy));
}
+ if (this.mSecurityEndpoints != null) {
+ appInfoEle.appendChild(
+ XmlUtils.createOdArray(
+ doc,
+ XmlUtils.OD_TAG_STRING_ARRAY,
+ XmlUtils.OD_NAME_SECURITY_ENDPOINTS,
+ mSecurityEndpoints));
+ }
if (this.mFirstPartyEndpoints != null) {
appInfoEle.appendChild(
XmlUtils.createOdArray(
@@ -71,27 +142,88 @@ public class AppInfo implements AslMarshallable {
XmlUtils.OD_NAME_SERVICE_PROVIDER_ENDPOINTS,
mServiceProviderEndpoints));
}
- return XmlUtils.listOf(appInfoEle);
+ if (this.mCategory != null) {
+ appInfoEle.appendChild(
+ XmlUtils.createOdStringEle(doc, XmlUtils.OD_NAME_CATEGORY, this.mCategory));
+ }
+ if (this.mEmail != null) {
+ appInfoEle.appendChild(
+ XmlUtils.createOdStringEle(doc, XmlUtils.OD_NAME_EMAIL, this.mEmail));
+ }
+ if (this.mWebsite != null) {
+ appInfoEle.appendChild(
+ XmlUtils.createOdStringEle(doc, XmlUtils.OD_NAME_WEBSITE, this.mWebsite));
+ }
+
+ if (this.mApsCompliant != null) {
+ appInfoEle.appendChild(
+ XmlUtils.createOdBooleanEle(
+ doc, XmlUtils.OD_NAME_APS_COMPLIANT, mApsCompliant));
+ }
+ if (this.mDeveloperId != null) {
+ appInfoEle.appendChild(
+ XmlUtils.createOdStringEle(doc, XmlUtils.OD_NAME_DEVELOPER_ID, mDeveloperId));
+ }
+ if (this.mApplicationId != null) {
+ appInfoEle.appendChild(
+ XmlUtils.createOdStringEle(
+ doc, XmlUtils.OD_NAME_APPLICATION_ID, mApplicationId));
+ }
+ return appInfoEle;
}
/** Creates the human-readable DOM elements from the AslMarshallable Java Object. */
- @Override
- public List<Element> toHrDomElements(Document doc) {
+ public Element toHrDomElement(Document doc) {
Element appInfoEle = doc.createElement(XmlUtils.HR_TAG_APP_INFO);
- if (this.mApsCompliant != null) {
+
+ if (this.mTitle != null) {
+ appInfoEle.setAttribute(XmlUtils.HR_ATTR_TITLE, this.mTitle);
+ }
+ if (this.mDescription != null) {
+ appInfoEle.setAttribute(XmlUtils.HR_ATTR_DESCRIPTION, this.mDescription);
+ }
+ if (this.mContainsAds != null) {
appInfoEle.setAttribute(
- XmlUtils.HR_ATTR_APS_COMPLIANT, String.valueOf(this.mApsCompliant));
+ XmlUtils.HR_ATTR_CONTAINS_ADS, String.valueOf(this.mContainsAds));
+ }
+ if (this.mObeyAps != null) {
+ appInfoEle.setAttribute(XmlUtils.HR_ATTR_OBEY_APS, String.valueOf(this.mObeyAps));
+ }
+ if (this.mAdsFingerprinting != null) {
+ appInfoEle.setAttribute(
+ XmlUtils.HR_ATTR_ADS_FINGERPRINTING, String.valueOf(this.mAdsFingerprinting));
+ }
+ if (this.mSecurityFingerprinting != null) {
+ appInfoEle.setAttribute(
+ XmlUtils.HR_ATTR_SECURITY_FINGERPRINTING,
+ String.valueOf(this.mSecurityFingerprinting));
}
if (this.mPrivacyPolicy != null) {
appInfoEle.setAttribute(XmlUtils.HR_ATTR_PRIVACY_POLICY, this.mPrivacyPolicy);
}
+ if (this.mSecurityEndpoints != null) {
+ appInfoEle.setAttribute(
+ XmlUtils.HR_ATTR_SECURITY_ENDPOINTS, String.join("|", this.mSecurityEndpoints));
+ }
+ if (this.mCategory != null) {
+ appInfoEle.setAttribute(XmlUtils.HR_ATTR_CATEGORY, this.mCategory);
+ }
+ if (this.mEmail != null) {
+ appInfoEle.setAttribute(XmlUtils.HR_ATTR_EMAIL, this.mEmail);
+ }
+ if (this.mWebsite != null) {
+ appInfoEle.setAttribute(XmlUtils.HR_ATTR_WEBSITE, this.mWebsite);
+ }
+ if (this.mApsCompliant != null) {
+ appInfoEle.setAttribute(
+ XmlUtils.HR_ATTR_APS_COMPLIANT, String.valueOf(this.mApsCompliant));
+ }
if (this.mFirstPartyEndpoints != null) {
appInfoEle.appendChild(
XmlUtils.createHrArray(
doc, XmlUtils.HR_TAG_FIRST_PARTY_ENDPOINTS, mFirstPartyEndpoints));
}
-
if (this.mServiceProviderEndpoints != null) {
appInfoEle.appendChild(
XmlUtils.createHrArray(
@@ -99,7 +231,13 @@ public class AppInfo implements AslMarshallable {
XmlUtils.HR_TAG_SERVICE_PROVIDER_ENDPOINTS,
mServiceProviderEndpoints));
}
+ if (this.mDeveloperId != null) {
+ appInfoEle.setAttribute(XmlUtils.HR_ATTR_DEVELOPER_ID, this.mDeveloperId);
+ }
+ if (this.mApplicationId != null) {
+ appInfoEle.setAttribute(XmlUtils.HR_ATTR_APPLICATION_ID, this.mApplicationId);
+ }
- return XmlUtils.listOf(appInfoEle);
+ return appInfoEle;
}
}
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AppInfoFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AppInfoFactory.java
index 6ad202765218..277a508ced57 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AppInfoFactory.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AppInfoFactory.java
@@ -16,60 +16,233 @@
package com.android.asllib.marshallable;
-import com.android.asllib.util.AslgenUtil;
import com.android.asllib.util.MalformedXmlException;
import com.android.asllib.util.XmlUtils;
import org.w3c.dom.Element;
import java.util.List;
+import java.util.Map;
+import java.util.Set;
public class AppInfoFactory implements AslMarshallableFactory<AppInfo> {
+ // We don't need to support V1 for HR.
+ private final Map<Long, Set<String>> mRecognizedHrAttrs =
+ Map.ofEntries(
+ Map.entry(
+ 2L,
+ Set.of(
+ XmlUtils.HR_ATTR_APS_COMPLIANT,
+ XmlUtils.HR_ATTR_PRIVACY_POLICY,
+ XmlUtils.HR_ATTR_DEVELOPER_ID,
+ XmlUtils.HR_ATTR_APPLICATION_ID)));
+ private final Map<Long, Set<String>> mRequiredHrAttrs =
+ Map.ofEntries(
+ Map.entry(
+ 2L,
+ Set.of(
+ XmlUtils.HR_ATTR_APS_COMPLIANT,
+ XmlUtils.HR_ATTR_PRIVACY_POLICY,
+ XmlUtils.HR_ATTR_DEVELOPER_ID,
+ XmlUtils.HR_ATTR_APPLICATION_ID)));
+ private final Map<Long, Set<String>> mRecognizedHrEles =
+ Map.ofEntries(
+ Map.entry(
+ 2L,
+ Set.of(
+ XmlUtils.HR_TAG_FIRST_PARTY_ENDPOINTS,
+ XmlUtils.HR_TAG_SERVICE_PROVIDER_ENDPOINTS)));
+ private final Map<Long, Set<String>> mRequiredHrEles =
+ Map.ofEntries(
+ Map.entry(
+ 2L,
+ Set.of(
+ XmlUtils.HR_TAG_FIRST_PARTY_ENDPOINTS,
+ XmlUtils.HR_TAG_SERVICE_PROVIDER_ENDPOINTS)));
+ private final Map<Long, Set<String>> mRecognizedOdEleNames =
+ Map.ofEntries(
+ Map.entry(
+ 1L,
+ Set.of(
+ XmlUtils.OD_NAME_TITLE,
+ XmlUtils.OD_NAME_DESCRIPTION,
+ XmlUtils.OD_NAME_CONTAINS_ADS,
+ XmlUtils.OD_NAME_OBEY_APS,
+ XmlUtils.OD_NAME_ADS_FINGERPRINTING,
+ XmlUtils.OD_NAME_SECURITY_FINGERPRINTING,
+ XmlUtils.OD_NAME_PRIVACY_POLICY,
+ XmlUtils.OD_NAME_SECURITY_ENDPOINTS,
+ XmlUtils.OD_NAME_FIRST_PARTY_ENDPOINTS,
+ XmlUtils.OD_NAME_SERVICE_PROVIDER_ENDPOINTS,
+ XmlUtils.OD_NAME_CATEGORY,
+ XmlUtils.OD_NAME_EMAIL,
+ XmlUtils.OD_NAME_WEBSITE)),
+ Map.entry(
+ 2L,
+ Set.of(
+ XmlUtils.OD_NAME_APS_COMPLIANT,
+ XmlUtils.OD_NAME_PRIVACY_POLICY,
+ XmlUtils.OD_NAME_FIRST_PARTY_ENDPOINTS,
+ XmlUtils.OD_NAME_SERVICE_PROVIDER_ENDPOINTS,
+ XmlUtils.OD_NAME_DEVELOPER_ID,
+ XmlUtils.OD_NAME_APPLICATION_ID)));
+ private final Map<Long, Set<String>> mRequiredOdEles =
+ Map.ofEntries(
+ Map.entry(
+ 1L,
+ Set.of(
+ XmlUtils.OD_NAME_TITLE,
+ XmlUtils.OD_NAME_DESCRIPTION,
+ XmlUtils.OD_NAME_CONTAINS_ADS,
+ XmlUtils.OD_NAME_OBEY_APS,
+ XmlUtils.OD_NAME_ADS_FINGERPRINTING,
+ XmlUtils.OD_NAME_SECURITY_FINGERPRINTING,
+ XmlUtils.OD_NAME_PRIVACY_POLICY,
+ XmlUtils.OD_NAME_SECURITY_ENDPOINTS,
+ XmlUtils.OD_NAME_FIRST_PARTY_ENDPOINTS,
+ XmlUtils.OD_NAME_SERVICE_PROVIDER_ENDPOINTS,
+ XmlUtils.OD_NAME_CATEGORY)),
+ Map.entry(
+ 2L,
+ Set.of(
+ XmlUtils.OD_NAME_APS_COMPLIANT,
+ XmlUtils.OD_NAME_PRIVACY_POLICY,
+ XmlUtils.OD_NAME_FIRST_PARTY_ENDPOINTS,
+ XmlUtils.OD_NAME_SERVICE_PROVIDER_ENDPOINTS,
+ XmlUtils.OD_NAME_DEVELOPER_ID,
+ XmlUtils.OD_NAME_APPLICATION_ID)));
/** Creates a {@link AppInfo} from the human-readable DOM element. */
- @Override
- public AppInfo createFromHrElements(List<Element> elements) throws MalformedXmlException {
- Element appInfoEle = XmlUtils.getSingleElement(elements);
- if (appInfoEle == null) {
- AslgenUtil.logI("No AppInfo found in hr format.");
- return null;
- }
+ public AppInfo createFromHrElement(Element appInfoEle, long version)
+ throws MalformedXmlException {
+ XmlUtils.throwIfExtraneousAttributes(
+ appInfoEle, XmlUtils.getMostRecentVersion(mRecognizedHrAttrs, version));
+ XmlUtils.throwIfExtraneousChildrenHr(
+ appInfoEle, XmlUtils.getMostRecentVersion(mRecognizedHrEles, version));
- Boolean apsCompliant =
- XmlUtils.getBoolAttr(appInfoEle, XmlUtils.HR_ATTR_APS_COMPLIANT, true);
+ var requiredHrAttrs = XmlUtils.getMostRecentVersion(mRequiredHrAttrs, version);
+ var requiredHrEles = XmlUtils.getMostRecentVersion(mRequiredHrEles, version);
+
+ String title = XmlUtils.getStringAttr(appInfoEle, XmlUtils.HR_ATTR_TITLE, requiredHrAttrs);
+ String description =
+ XmlUtils.getStringAttr(appInfoEle, XmlUtils.HR_ATTR_DESCRIPTION, requiredHrAttrs);
+ Boolean containsAds =
+ XmlUtils.getBoolAttr(appInfoEle, XmlUtils.HR_ATTR_CONTAINS_ADS, requiredHrAttrs);
+ Boolean obeyAps =
+ XmlUtils.getBoolAttr(appInfoEle, XmlUtils.HR_ATTR_OBEY_APS, requiredHrAttrs);
+ Boolean adsFingerprinting =
+ XmlUtils.getBoolAttr(
+ appInfoEle, XmlUtils.HR_ATTR_ADS_FINGERPRINTING, requiredHrAttrs);
+ Boolean securityFingerprinting =
+ XmlUtils.getBoolAttr(
+ appInfoEle, XmlUtils.HR_ATTR_SECURITY_FINGERPRINTING, requiredHrAttrs);
String privacyPolicy =
- XmlUtils.getStringAttr(appInfoEle, XmlUtils.HR_ATTR_PRIVACY_POLICY, true);
+ XmlUtils.getStringAttr(
+ appInfoEle, XmlUtils.HR_ATTR_PRIVACY_POLICY, requiredHrAttrs);
+ List<String> securityEndpoints =
+ XmlUtils.getPipelineSplitAttr(
+ appInfoEle, XmlUtils.HR_ATTR_SECURITY_ENDPOINTS, requiredHrAttrs);
+ String category =
+ XmlUtils.getStringAttr(appInfoEle, XmlUtils.HR_ATTR_CATEGORY, requiredHrAttrs);
+ String email = XmlUtils.getStringAttr(appInfoEle, XmlUtils.HR_ATTR_EMAIL, requiredHrAttrs);
+ String website =
+ XmlUtils.getStringAttr(appInfoEle, XmlUtils.HR_ATTR_WEBSITE, requiredHrAttrs);
+ String developerId =
+ XmlUtils.getStringAttr(appInfoEle, XmlUtils.HR_ATTR_DEVELOPER_ID, requiredHrAttrs);
+ String applicationId =
+ XmlUtils.getStringAttr(
+ appInfoEle, XmlUtils.HR_ATTR_APPLICATION_ID, requiredHrAttrs);
+
+ Boolean apsCompliant =
+ XmlUtils.getBoolAttr(appInfoEle, XmlUtils.HR_ATTR_APS_COMPLIANT, requiredHrAttrs);
List<String> firstPartyEndpoints =
XmlUtils.getHrItemsAsStrings(
- appInfoEle, XmlUtils.HR_TAG_FIRST_PARTY_ENDPOINTS, true);
+ appInfoEle, XmlUtils.HR_TAG_FIRST_PARTY_ENDPOINTS, requiredHrEles);
List<String> serviceProviderEndpoints =
XmlUtils.getHrItemsAsStrings(
- appInfoEle, XmlUtils.HR_TAG_SERVICE_PROVIDER_ENDPOINTS, true);
+ appInfoEle, XmlUtils.HR_TAG_SERVICE_PROVIDER_ENDPOINTS, requiredHrEles);
return new AppInfo(
- apsCompliant, privacyPolicy, firstPartyEndpoints, serviceProviderEndpoints);
+ title,
+ description,
+ containsAds,
+ obeyAps,
+ adsFingerprinting,
+ securityFingerprinting,
+ privacyPolicy,
+ securityEndpoints,
+ firstPartyEndpoints,
+ serviceProviderEndpoints,
+ category,
+ email,
+ website,
+ apsCompliant,
+ developerId,
+ applicationId);
}
/** Creates an {@link AslMarshallableFactory} from on-device DOM elements */
- @Override
- public AppInfo createFromOdElements(List<Element> elements) throws MalformedXmlException {
- Element appInfoEle = XmlUtils.getSingleElement(elements);
- if (appInfoEle == null) {
- AslgenUtil.logI("No AppInfo found in od format.");
- return null;
- }
+ public AppInfo createFromOdElement(Element appInfoEle, long version)
+ throws MalformedXmlException {
+ XmlUtils.throwIfExtraneousChildrenOd(
+ appInfoEle, XmlUtils.getMostRecentVersion(mRecognizedOdEleNames, version));
+ var requiredOdEles = XmlUtils.getMostRecentVersion(mRequiredOdEles, version);
- Boolean apsCompliant =
- XmlUtils.getOdBoolEle(appInfoEle, XmlUtils.OD_NAME_APS_COMPLIANT, true);
+ String title = XmlUtils.getOdStringEle(appInfoEle, XmlUtils.OD_NAME_TITLE, requiredOdEles);
+ String description =
+ XmlUtils.getOdStringEle(appInfoEle, XmlUtils.OD_NAME_DESCRIPTION, requiredOdEles);
+ Boolean containsAds =
+ XmlUtils.getOdBoolEle(appInfoEle, XmlUtils.OD_NAME_CONTAINS_ADS, requiredOdEles);
+ Boolean obeyAps =
+ XmlUtils.getOdBoolEle(appInfoEle, XmlUtils.OD_NAME_OBEY_APS, requiredOdEles);
+ Boolean adsFingerprinting =
+ XmlUtils.getOdBoolEle(
+ appInfoEle, XmlUtils.OD_NAME_ADS_FINGERPRINTING, requiredOdEles);
+ Boolean securityFingerprinting =
+ XmlUtils.getOdBoolEle(
+ appInfoEle, XmlUtils.OD_NAME_SECURITY_FINGERPRINTING, requiredOdEles);
String privacyPolicy =
- XmlUtils.getOdStringEle(appInfoEle, XmlUtils.OD_NAME_PRIVACY_POLICY, true);
+ XmlUtils.getOdStringEle(
+ appInfoEle, XmlUtils.OD_NAME_PRIVACY_POLICY, requiredOdEles);
+ List<String> securityEndpoints =
+ XmlUtils.getOdStringArray(
+ appInfoEle, XmlUtils.OD_NAME_SECURITY_ENDPOINTS, requiredOdEles);
+ String category =
+ XmlUtils.getOdStringEle(appInfoEle, XmlUtils.OD_NAME_CATEGORY, requiredOdEles);
+ String email = XmlUtils.getOdStringEle(appInfoEle, XmlUtils.OD_NAME_EMAIL, requiredOdEles);
+ String website =
+ XmlUtils.getOdStringEle(appInfoEle, XmlUtils.OD_NAME_WEBSITE, requiredOdEles);
+ String developerId =
+ XmlUtils.getOdStringEle(appInfoEle, XmlUtils.OD_NAME_DEVELOPER_ID, requiredOdEles);
+ String applicationId =
+ XmlUtils.getOdStringEle(
+ appInfoEle, XmlUtils.OD_NAME_APPLICATION_ID, requiredOdEles);
+
+ Boolean apsCompliant =
+ XmlUtils.getOdBoolEle(appInfoEle, XmlUtils.OD_NAME_APS_COMPLIANT, requiredOdEles);
List<String> firstPartyEndpoints =
- XmlUtils.getOdStringArray(appInfoEle, XmlUtils.OD_NAME_FIRST_PARTY_ENDPOINTS, true);
+ XmlUtils.getOdStringArray(
+ appInfoEle, XmlUtils.OD_NAME_FIRST_PARTY_ENDPOINTS, requiredOdEles);
List<String> serviceProviderEndpoints =
XmlUtils.getOdStringArray(
- appInfoEle, XmlUtils.OD_NAME_SERVICE_PROVIDER_ENDPOINTS, true);
+ appInfoEle, XmlUtils.OD_NAME_SERVICE_PROVIDER_ENDPOINTS, requiredOdEles);
return new AppInfo(
- apsCompliant, privacyPolicy, firstPartyEndpoints, serviceProviderEndpoints);
+ title,
+ description,
+ containsAds,
+ obeyAps,
+ adsFingerprinting,
+ securityFingerprinting,
+ privacyPolicy,
+ securityEndpoints,
+ firstPartyEndpoints,
+ serviceProviderEndpoints,
+ category,
+ email,
+ website,
+ apsCompliant,
+ developerId,
+ applicationId);
}
}
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AslMarshallable.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AslMarshallable.java
index 0a70e7d0d74b..b6c789dc5ec7 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AslMarshallable.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AslMarshallable.java
@@ -16,16 +16,11 @@
package com.android.asllib.marshallable;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-
-import java.util.List;
-
public interface AslMarshallable {
/** Creates the on-device DOM elements from the AslMarshallable Java Object. */
- List<Element> toOdDomElements(Document doc);
+ // List<Element> toOdDomElements(Document doc);
/** Creates the human-readable DOM elements from the AslMarshallable Java Object. */
- List<Element> toHrDomElements(Document doc);
+ // List<Element> toHrDomElements(Document doc);
}
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AslMarshallableFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AslMarshallableFactory.java
index 39582900f3a0..67f106948e79 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AslMarshallableFactory.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AslMarshallableFactory.java
@@ -16,17 +16,11 @@
package com.android.asllib.marshallable;
-import com.android.asllib.util.MalformedXmlException;
-
-import org.w3c.dom.Element;
-
-import java.util.List;
-
public interface AslMarshallableFactory<T extends AslMarshallable> {
/** Creates an {@link AslMarshallableFactory} from human-readable DOM elements */
- T createFromHrElements(List<Element> elements) throws MalformedXmlException;
+ // T createFromHrElements(List<Element> elements) throws MalformedXmlException;
/** Creates an {@link AslMarshallableFactory} from on-device DOM elements */
- T createFromOdElements(List<Element> elements) throws MalformedXmlException;
+ // T createFromOdElements(List<Element> elements) throws MalformedXmlException;
}
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataCategory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataCategory.java
index c16d18b34360..501f170ad317 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataCategory.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataCategory.java
@@ -57,18 +57,16 @@ public class DataCategory implements AslMarshallable {
}
/** Creates on-device DOM element(s) from the {@link DataCategory}. */
- @Override
- public List<Element> toOdDomElements(Document doc) {
+ public Element toOdDomElement(Document doc) {
Element dataCategoryEle = XmlUtils.createPbundleEleWithName(doc, this.getCategoryName());
for (DataType dataType : mDataTypes.values()) {
- XmlUtils.appendChildren(dataCategoryEle, dataType.toOdDomElements(doc));
+ dataCategoryEle.appendChild(dataType.toOdDomElement(doc));
}
- return XmlUtils.listOf(dataCategoryEle);
+ return dataCategoryEle;
}
/** Creates the human-readable DOM elements from the AslMarshallable Java Object. */
- @Override
- public List<Element> toHrDomElements(Document doc) {
+ public List<Element> toHrDomElement(Document doc) {
throw new IllegalStateException(
"Turning DataCategory or DataType into human-readable DOM elements requires"
+ " visibility into parent elements. The logic resides in DataLabels.");
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataCategoryFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataCategoryFactory.java
index 724416285acd..fb84e508ff7f 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataCategoryFactory.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataCategoryFactory.java
@@ -23,13 +23,11 @@ import com.android.asllib.util.XmlUtils;
import org.w3c.dom.Element;
import java.util.LinkedHashMap;
-import java.util.List;
import java.util.Map;
public class DataCategoryFactory {
/** Creates an {@link AslMarshallableFactory} from on-device DOM elements */
- public DataCategory createFromOdElements(List<Element> elements) throws MalformedXmlException {
- Element dataCategoryEle = XmlUtils.getSingleElement(elements);
+ public DataCategory createFromOdElement(Element dataCategoryEle) throws MalformedXmlException {
Map<String, DataType> dataTypeMap = new LinkedHashMap<String, DataType>();
String categoryName = dataCategoryEle.getAttribute(XmlUtils.OD_ATTR_NAME);
var odDataTypes = XmlUtils.asElementList(dataCategoryEle.getChildNodes());
@@ -45,9 +43,7 @@ public class DataCategoryFactory {
"Unrecognized data type name %s for category %s",
dataTypeName, categoryName));
}
- dataTypeMap.put(
- dataTypeName,
- new DataTypeFactory().createFromOdElements(XmlUtils.listOf(odDataTypeEle)));
+ dataTypeMap.put(dataTypeName, new DataTypeFactory().createFromOdElement(odDataTypeEle));
}
return new DataCategory(categoryName, dataTypeMap);
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataLabels.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataLabels.java
index 3c93c88cd060..2cf7c82fdb3e 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataLabels.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataLabels.java
@@ -22,7 +22,6 @@ import com.android.asllib.util.XmlUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
-import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@@ -57,20 +56,18 @@ public class DataLabels implements AslMarshallable {
}
/** Gets the on-device DOM element for the {@link DataLabels}. */
- @Override
- public List<Element> toOdDomElements(Document doc) {
+ public Element toOdDomElement(Document doc) {
Element dataLabelsEle =
XmlUtils.createPbundleEleWithName(doc, XmlUtils.OD_NAME_DATA_LABELS);
maybeAppendDataUsages(doc, dataLabelsEle, mDataCollected, XmlUtils.OD_NAME_DATA_COLLECTED);
maybeAppendDataUsages(doc, dataLabelsEle, mDataShared, XmlUtils.OD_NAME_DATA_SHARED);
- return XmlUtils.listOf(dataLabelsEle);
+ return dataLabelsEle;
}
/** Creates the human-readable DOM elements from the AslMarshallable Java Object. */
- @Override
- public List<Element> toHrDomElements(Document doc) {
+ public Element toHrDomElement(Document doc) {
Element dataLabelsEle = doc.createElement(XmlUtils.HR_TAG_DATA_LABELS);
maybeAppendHrDataUsages(
doc, dataLabelsEle, mDataCollected, XmlUtils.HR_TAG_DATA_COLLECTED, false);
@@ -78,7 +75,7 @@ public class DataLabels implements AslMarshallable {
doc, dataLabelsEle, mDataCollected, XmlUtils.HR_TAG_DATA_COLLECTED_EPHEMERAL, true);
maybeAppendHrDataUsages(
doc, dataLabelsEle, mDataShared, XmlUtils.HR_TAG_DATA_SHARED, false);
- return XmlUtils.listOf(dataLabelsEle);
+ return dataLabelsEle;
}
private void maybeAppendDataUsages(
@@ -96,7 +93,7 @@ public class DataLabels implements AslMarshallable {
DataCategory dataCategory = dataCategoriesMap.get(dataCategoryName);
for (String dataTypeName : dataCategory.getDataTypes().keySet()) {
DataType dataType = dataCategory.getDataTypes().get(dataTypeName);
- XmlUtils.appendChildren(dataCategoryEle, dataType.toOdDomElements(doc));
+ dataCategoryEle.appendChild(dataType.toOdDomElement(doc));
}
dataUsageEle.appendChild(dataCategoryEle);
}
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataLabelsFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataLabelsFactory.java
index c4d88761835a..b1cf3ea0d39a 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataLabelsFactory.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataLabelsFactory.java
@@ -31,9 +31,7 @@ import java.util.Map;
public class DataLabelsFactory implements AslMarshallableFactory<DataLabels> {
/** Creates a {@link DataLabels} from the human-readable DOM element. */
- @Override
- public DataLabels createFromHrElements(List<Element> elements) throws MalformedXmlException {
- Element ele = XmlUtils.getSingleElement(elements);
+ public DataLabels createFromHrElement(Element ele) throws MalformedXmlException {
if (ele == null) {
AslgenUtil.logI("Found no DataLabels in hr format.");
return null;
@@ -83,9 +81,7 @@ public class DataLabelsFactory implements AslMarshallableFactory<DataLabels> {
}
/** Creates an {@link AslMarshallableFactory} from on-device DOM elements */
- @Override
- public DataLabels createFromOdElements(List<Element> elements) throws MalformedXmlException {
- Element dataLabelsEle = XmlUtils.getSingleElement(elements);
+ public DataLabels createFromOdElement(Element dataLabelsEle) throws MalformedXmlException {
if (dataLabelsEle == null) {
AslgenUtil.logI("Found no DataLabels in od format.");
return null;
@@ -111,7 +107,7 @@ public class DataLabelsFactory implements AslMarshallableFactory<DataLabels> {
for (Element dataCategoryEle : dataCategoryEles) {
String dataCategoryName = dataCategoryEle.getAttribute(XmlUtils.OD_ATTR_NAME);
DataCategory dataCategory =
- new DataCategoryFactory().createFromOdElements(List.of(dataCategoryEle));
+ new DataCategoryFactory().createFromOdElement(dataCategoryEle);
dataCategoryMap.put(dataCategoryName, dataCategory);
}
return dataCategoryMap;
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataType.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataType.java
index 284a4b804435..83bb61144efa 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataType.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataType.java
@@ -172,8 +172,8 @@ public class DataType implements AslMarshallable {
return mEphemeral;
}
- @Override
- public List<Element> toOdDomElements(Document doc) {
+ /** Gets the on-device dom element */
+ public Element toOdDomElement(Document doc) {
Element dataTypeEle = XmlUtils.createPbundleEleWithName(doc, this.getDataTypeName());
if (!this.getPurposes().isEmpty()) {
dataTypeEle.appendChild(
@@ -197,11 +197,10 @@ public class DataType implements AslMarshallable {
this.getIsSharingOptional(),
XmlUtils.OD_NAME_IS_SHARING_OPTIONAL);
maybeAddBoolToOdElement(doc, dataTypeEle, this.getEphemeral(), XmlUtils.OD_NAME_EPHEMERAL);
- return XmlUtils.listOf(dataTypeEle);
+ return dataTypeEle;
}
/** Creates the human-readable DOM elements from the AslMarshallable Java Object. */
- @Override
public List<Element> toHrDomElements(Document doc) {
throw new IllegalStateException(
"Turning DataCategory or DataType into human-readable DOM elements requires"
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataTypeFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataTypeFactory.java
index a5559d801349..96a58fa34707 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataTypeFactory.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataTypeFactory.java
@@ -64,8 +64,7 @@ public class DataTypeFactory {
}
/** Creates an {@link AslMarshallableFactory} from on-device DOM elements */
- public DataType createFromOdElements(List<Element> elements) throws MalformedXmlException {
- Element odDataTypeEle = XmlUtils.getSingleElement(elements);
+ public DataType createFromOdElement(Element odDataTypeEle) throws MalformedXmlException {
String dataTypeName = odDataTypeEle.getAttribute(XmlUtils.OD_ATTR_NAME);
List<Integer> purposeInts =
XmlUtils.getOdIntArray(odDataTypeEle, XmlUtils.OD_NAME_PURPOSES, true);
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DeveloperInfo.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DeveloperInfo.java
new file mode 100644
index 000000000000..96a64dc29526
--- /dev/null
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DeveloperInfo.java
@@ -0,0 +1,167 @@
+/*
+ * 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.asllib.marshallable;
+
+import com.android.asllib.util.XmlUtils;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+/** DeveloperInfo representation */
+public class DeveloperInfo implements AslMarshallable {
+ public enum DeveloperRelationship {
+ OEM(0),
+ ODM(1),
+ SOC(2),
+ OTA(3),
+ CARRIER(4),
+ AOSP(5),
+ OTHER(6);
+
+ private final int mValue;
+
+ DeveloperRelationship(int value) {
+ this.mValue = value;
+ }
+
+ /** Get the int value associated with the DeveloperRelationship. */
+ public int getValue() {
+ return mValue;
+ }
+
+ /** Get the DeveloperRelationship associated with the int value. */
+ public static DeveloperInfo.DeveloperRelationship forValue(int value) {
+ for (DeveloperInfo.DeveloperRelationship e : values()) {
+ if (e.getValue() == value) {
+ return e;
+ }
+ }
+ throw new IllegalArgumentException("No DeveloperRelationship enum for value: " + value);
+ }
+
+ /** Get the DeveloperRelationship associated with the human-readable String. */
+ public static DeveloperInfo.DeveloperRelationship forString(String s) {
+ for (DeveloperInfo.DeveloperRelationship e : values()) {
+ if (e.toString().equals(s)) {
+ return e;
+ }
+ }
+ throw new IllegalArgumentException("No DeveloperRelationship enum for str: " + s);
+ }
+
+ /** Human-readable String representation of DeveloperRelationship. */
+ public String toString() {
+ return this.name().toLowerCase();
+ }
+ }
+
+ private final String mName;
+ private final String mEmail;
+ private final String mAddress;
+ private final String mCountryRegion;
+ private final DeveloperRelationship mDeveloperRelationship;
+ private final String mWebsite;
+ private final String mAppDeveloperRegistryId;
+
+ public DeveloperInfo(
+ String name,
+ String email,
+ String address,
+ String countryRegion,
+ DeveloperRelationship developerRelationship,
+ String website,
+ String appDeveloperRegistryId) {
+ this.mName = name;
+ this.mEmail = email;
+ this.mAddress = address;
+ this.mCountryRegion = countryRegion;
+ this.mDeveloperRelationship = developerRelationship;
+ this.mWebsite = website;
+ this.mAppDeveloperRegistryId = appDeveloperRegistryId;
+ }
+
+ /** Creates an on-device DOM element from the {@link SafetyLabels}. */
+ public Element toOdDomElement(Document doc) {
+ Element developerInfoEle =
+ XmlUtils.createPbundleEleWithName(doc, XmlUtils.OD_NAME_DEVELOPER_INFO);
+ if (mName != null) {
+ developerInfoEle.appendChild(
+ XmlUtils.createOdStringEle(doc, XmlUtils.OD_NAME_NAME, mName));
+ }
+ if (mEmail != null) {
+ developerInfoEle.appendChild(
+ XmlUtils.createOdStringEle(doc, XmlUtils.OD_NAME_EMAIL, mEmail));
+ }
+ if (mAddress != null) {
+ developerInfoEle.appendChild(
+ XmlUtils.createOdStringEle(doc, XmlUtils.OD_NAME_ADDRESS, mAddress));
+ }
+ if (mCountryRegion != null) {
+ developerInfoEle.appendChild(
+ XmlUtils.createOdStringEle(
+ doc, XmlUtils.OD_NAME_COUNTRY_REGION, mCountryRegion));
+ }
+ if (mDeveloperRelationship != null) {
+ developerInfoEle.appendChild(
+ XmlUtils.createOdLongEle(
+ doc,
+ XmlUtils.OD_NAME_DEVELOPER_RELATIONSHIP,
+ mDeveloperRelationship.getValue()));
+ }
+ if (mWebsite != null) {
+ developerInfoEle.appendChild(
+ XmlUtils.createOdStringEle(doc, XmlUtils.OD_NAME_WEBSITE, mWebsite));
+ }
+ if (mAppDeveloperRegistryId != null) {
+ developerInfoEle.appendChild(
+ XmlUtils.createOdStringEle(
+ doc,
+ XmlUtils.OD_NAME_APP_DEVELOPER_REGISTRY_ID,
+ mAppDeveloperRegistryId));
+ }
+ return developerInfoEle;
+ }
+
+ /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */
+ public Element toHrDomElement(Document doc) {
+ Element developerInfoEle = doc.createElement(XmlUtils.HR_TAG_DEVELOPER_INFO);
+ if (mName != null) {
+ developerInfoEle.setAttribute(XmlUtils.HR_ATTR_NAME, mName);
+ }
+ if (mEmail != null) {
+ developerInfoEle.setAttribute(XmlUtils.HR_ATTR_EMAIL, mEmail);
+ }
+ if (mAddress != null) {
+ developerInfoEle.setAttribute(XmlUtils.HR_ATTR_ADDRESS, mAddress);
+ }
+ if (mCountryRegion != null) {
+ developerInfoEle.setAttribute(XmlUtils.HR_ATTR_COUNTRY_REGION, mCountryRegion);
+ }
+ if (mDeveloperRelationship != null) {
+ developerInfoEle.setAttribute(
+ XmlUtils.HR_ATTR_DEVELOPER_RELATIONSHIP, mDeveloperRelationship.toString());
+ }
+ if (mWebsite != null) {
+ developerInfoEle.setAttribute(XmlUtils.HR_ATTR_WEBSITE, mWebsite);
+ }
+ if (mAppDeveloperRegistryId != null) {
+ developerInfoEle.setAttribute(
+ XmlUtils.HR_ATTR_APP_DEVELOPER_REGISTRY_ID, mAppDeveloperRegistryId);
+ }
+ return developerInfoEle;
+ }
+}
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DeveloperInfoFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DeveloperInfoFactory.java
new file mode 100644
index 000000000000..e82a53a53b25
--- /dev/null
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DeveloperInfoFactory.java
@@ -0,0 +1,89 @@
+/*
+ * 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.asllib.marshallable;
+
+import com.android.asllib.util.AslgenUtil;
+import com.android.asllib.util.MalformedXmlException;
+import com.android.asllib.util.XmlUtils;
+
+import org.w3c.dom.Element;
+
+public class DeveloperInfoFactory implements AslMarshallableFactory<DeveloperInfo> {
+ /** Creates a {@link DeveloperInfo} from the human-readable DOM element. */
+ public DeveloperInfo createFromHrElement(Element developerInfoEle)
+ throws MalformedXmlException {
+ if (developerInfoEle == null) {
+ AslgenUtil.logI("No DeveloperInfo found in hr format.");
+ return null;
+ }
+ String name = XmlUtils.getStringAttr(developerInfoEle, XmlUtils.HR_ATTR_NAME, true);
+ String email = XmlUtils.getStringAttr(developerInfoEle, XmlUtils.HR_ATTR_EMAIL, true);
+ String address = XmlUtils.getStringAttr(developerInfoEle, XmlUtils.HR_ATTR_ADDRESS, true);
+ String countryRegion =
+ XmlUtils.getStringAttr(developerInfoEle, XmlUtils.HR_ATTR_COUNTRY_REGION, true);
+ DeveloperInfo.DeveloperRelationship developerRelationship =
+ DeveloperInfo.DeveloperRelationship.forString(
+ XmlUtils.getStringAttr(
+ developerInfoEle, XmlUtils.HR_ATTR_DEVELOPER_RELATIONSHIP, true));
+ String website = XmlUtils.getStringAttr(developerInfoEle, XmlUtils.HR_ATTR_WEBSITE, false);
+ String appDeveloperRegistryId =
+ XmlUtils.getStringAttr(
+ developerInfoEle, XmlUtils.HR_ATTR_APP_DEVELOPER_REGISTRY_ID, false);
+ return new DeveloperInfo(
+ name,
+ email,
+ address,
+ countryRegion,
+ developerRelationship,
+ website,
+ appDeveloperRegistryId);
+ }
+
+ /** Creates an {@link AslMarshallableFactory} from on-device DOM elements */
+ public DeveloperInfo createFromOdElement(Element developerInfoEle)
+ throws MalformedXmlException {
+ if (developerInfoEle == null) {
+ AslgenUtil.logI("No DeveloperInfo found in od format.");
+ return null;
+ }
+ String name = XmlUtils.getOdStringEle(developerInfoEle, XmlUtils.OD_NAME_NAME, true);
+ String email = XmlUtils.getOdStringEle(developerInfoEle, XmlUtils.OD_NAME_EMAIL, true);
+ String address = XmlUtils.getOdStringEle(developerInfoEle, XmlUtils.OD_NAME_ADDRESS, true);
+ String countryRegion =
+ XmlUtils.getOdStringEle(developerInfoEle, XmlUtils.OD_NAME_COUNTRY_REGION, true);
+ DeveloperInfo.DeveloperRelationship developerRelationship =
+ DeveloperInfo.DeveloperRelationship.forValue(
+ (int)
+ (long)
+ XmlUtils.getOdLongEle(
+ developerInfoEle,
+ XmlUtils.OD_NAME_DEVELOPER_RELATIONSHIP,
+ true));
+ String website = XmlUtils.getOdStringEle(developerInfoEle, XmlUtils.OD_NAME_WEBSITE, false);
+ String appDeveloperRegistryId =
+ XmlUtils.getOdStringEle(
+ developerInfoEle, XmlUtils.OD_NAME_APP_DEVELOPER_REGISTRY_ID, false);
+ return new DeveloperInfo(
+ name,
+ email,
+ address,
+ countryRegion,
+ developerRelationship,
+ website,
+ appDeveloperRegistryId);
+ }
+}
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SafetyLabels.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SafetyLabels.java
index 2a4e130981af..1a83c02de3e4 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SafetyLabels.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SafetyLabels.java
@@ -21,40 +21,50 @@ import com.android.asllib.util.XmlUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
-import java.util.List;
-
/** Safety Label representation containing zero or more {@link DataCategory} for data shared */
public class SafetyLabels implements AslMarshallable {
private final DataLabels mDataLabels;
+ private final SecurityLabels mSecurityLabels;
+ private final ThirdPartyVerification mThirdPartyVerification;
- public SafetyLabels(DataLabels dataLabels) {
+ public SafetyLabels(
+ DataLabels dataLabels,
+ SecurityLabels securityLabels,
+ ThirdPartyVerification thirdPartyVerification) {
this.mDataLabels = dataLabels;
- }
-
- /** Returns the data label for the safety label */
- public DataLabels getDataLabel() {
- return mDataLabels;
+ this.mSecurityLabels = securityLabels;
+ this.mThirdPartyVerification = thirdPartyVerification;
}
/** Creates an on-device DOM element from the {@link SafetyLabels}. */
- @Override
- public List<Element> toOdDomElements(Document doc) {
+ public Element toOdDomElement(Document doc) {
Element safetyLabelsEle =
XmlUtils.createPbundleEleWithName(doc, XmlUtils.OD_NAME_SAFETY_LABELS);
if (mDataLabels != null) {
- XmlUtils.appendChildren(safetyLabelsEle, mDataLabels.toOdDomElements(doc));
+ safetyLabelsEle.appendChild(mDataLabels.toOdDomElement(doc));
+ }
+ if (mSecurityLabels != null) {
+ safetyLabelsEle.appendChild(mSecurityLabels.toOdDomElement(doc));
}
- return XmlUtils.listOf(safetyLabelsEle);
+ if (mThirdPartyVerification != null) {
+ safetyLabelsEle.appendChild(mThirdPartyVerification.toOdDomElement(doc));
+ }
+ return safetyLabelsEle;
}
/** Creates the human-readable DOM elements from the AslMarshallable Java Object. */
- @Override
- public List<Element> toHrDomElements(Document doc) {
+ public Element toHrDomElement(Document doc) {
Element safetyLabelsEle = doc.createElement(XmlUtils.HR_TAG_SAFETY_LABELS);
if (mDataLabels != null) {
- XmlUtils.appendChildren(safetyLabelsEle, mDataLabels.toHrDomElements(doc));
+ safetyLabelsEle.appendChild(mDataLabels.toHrDomElement(doc));
+ }
+ if (mSecurityLabels != null) {
+ safetyLabelsEle.appendChild(mSecurityLabels.toHrDomElement(doc));
+ }
+ if (mThirdPartyVerification != null) {
+ safetyLabelsEle.appendChild(mThirdPartyVerification.toHrDomElement(doc));
}
- return XmlUtils.listOf(safetyLabelsEle);
+ return safetyLabelsEle;
}
}
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SafetyLabelsFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SafetyLabelsFactory.java
index 2738337b7080..35804d9351b4 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SafetyLabelsFactory.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SafetyLabelsFactory.java
@@ -16,54 +16,109 @@
package com.android.asllib.marshallable;
-import com.android.asllib.util.AslgenUtil;
import com.android.asllib.util.MalformedXmlException;
import com.android.asllib.util.XmlUtils;
import org.w3c.dom.Element;
-import java.util.List;
+import java.util.Map;
+import java.util.Set;
public class SafetyLabelsFactory implements AslMarshallableFactory<SafetyLabels> {
+ private final Map<Long, Set<String>> mRecognizedHrAttrs =
+ Map.ofEntries(Map.entry(1L, Set.of()));
+ private final Map<Long, Set<String>> mRequiredHrAttrs = Map.ofEntries(Map.entry(1L, Set.of()));
+ private final Map<Long, Set<String>> mRecognizedHrEles =
+ Map.ofEntries(
+ Map.entry(
+ 1L,
+ Set.of(
+ XmlUtils.HR_TAG_DATA_LABELS,
+ XmlUtils.HR_TAG_SECURITY_LABELS,
+ XmlUtils.HR_TAG_THIRD_PARTY_VERIFICATION)),
+ Map.entry(2L, Set.of(XmlUtils.HR_TAG_DATA_LABELS)));
+ private final Map<Long, Set<String>> mRequiredHrEles = Map.ofEntries(Map.entry(1L, Set.of()));
+ private final Map<Long, Set<String>> mRecognizedOdEleNames =
+ Map.ofEntries(
+ Map.entry(
+ 1L,
+ Set.of(
+ XmlUtils.OD_NAME_DATA_LABELS,
+ XmlUtils.OD_NAME_SECURITY_LABELS,
+ XmlUtils.OD_NAME_THIRD_PARTY_VERIFICATION)),
+ Map.entry(2L, Set.of(XmlUtils.OD_NAME_DATA_LABELS)));
+ private final Map<Long, Set<String>> mRequiredOdEles = Map.ofEntries(Map.entry(1L, Set.of()));
/** Creates a {@link SafetyLabels} from the human-readable DOM element. */
- @Override
- public SafetyLabels createFromHrElements(List<Element> elements) throws MalformedXmlException {
- Element safetyLabelsEle = XmlUtils.getSingleElement(elements);
+ public SafetyLabels createFromHrElement(Element safetyLabelsEle, long version)
+ throws MalformedXmlException {
if (safetyLabelsEle == null) {
- AslgenUtil.logI("No SafetyLabels found in hr format.");
return null;
}
+ XmlUtils.throwIfExtraneousAttributes(
+ safetyLabelsEle, XmlUtils.getMostRecentVersion(mRecognizedHrAttrs, version));
+ XmlUtils.throwIfExtraneousChildrenHr(
+ safetyLabelsEle, XmlUtils.getMostRecentVersion(mRecognizedHrEles, version));
+
+ var requiredHrEles = XmlUtils.getMostRecentVersion(mRequiredHrEles, version);
+
DataLabels dataLabels =
new DataLabelsFactory()
- .createFromHrElements(
- XmlUtils.listOf(
- XmlUtils.getSingleChildElement(
- safetyLabelsEle,
- XmlUtils.HR_TAG_DATA_LABELS,
- false)));
- return new SafetyLabels(dataLabels);
+ .createFromHrElement(
+ XmlUtils.getSingleChildElement(
+ safetyLabelsEle,
+ XmlUtils.HR_TAG_DATA_LABELS,
+ requiredHrEles));
+ SecurityLabels securityLabels =
+ new SecurityLabelsFactory()
+ .createFromHrElement(
+ XmlUtils.getSingleChildElement(
+ safetyLabelsEle,
+ XmlUtils.HR_TAG_SECURITY_LABELS,
+ requiredHrEles));
+ ThirdPartyVerification thirdPartyVerification =
+ new ThirdPartyVerificationFactory()
+ .createFromHrElement(
+ XmlUtils.getSingleChildElement(
+ safetyLabelsEle,
+ XmlUtils.HR_TAG_THIRD_PARTY_VERIFICATION,
+ requiredHrEles));
+ return new SafetyLabels(dataLabels, securityLabels, thirdPartyVerification);
}
/** Creates an {@link AslMarshallableFactory} from on-device DOM elements */
- @Override
- public SafetyLabels createFromOdElements(List<Element> elements) throws MalformedXmlException {
- Element safetyLabelsEle = XmlUtils.getSingleElement(elements);
+ public SafetyLabels createFromOdElement(Element safetyLabelsEle, long version)
+ throws MalformedXmlException {
if (safetyLabelsEle == null) {
- AslgenUtil.logI("No SafetyLabels found in od format.");
return null;
}
+ XmlUtils.throwIfExtraneousChildrenOd(
+ safetyLabelsEle, XmlUtils.getMostRecentVersion(mRecognizedOdEleNames, version));
+ var requiredOdEles = XmlUtils.getMostRecentVersion(mRequiredOdEles, version);
+
DataLabels dataLabels =
new DataLabelsFactory()
- .createFromOdElements(
- XmlUtils.listOf(
- XmlUtils.getOdPbundleWithName(
- safetyLabelsEle,
- XmlUtils.OD_NAME_DATA_LABELS,
- false)));
-
- return new SafetyLabels(dataLabels);
+ .createFromOdElement(
+ XmlUtils.getOdPbundleWithName(
+ safetyLabelsEle,
+ XmlUtils.OD_NAME_DATA_LABELS,
+ requiredOdEles));
+ SecurityLabels securityLabels =
+ new SecurityLabelsFactory()
+ .createFromOdElement(
+ XmlUtils.getOdPbundleWithName(
+ safetyLabelsEle,
+ XmlUtils.OD_NAME_SECURITY_LABELS,
+ requiredOdEles));
+ ThirdPartyVerification thirdPartyVerification =
+ new ThirdPartyVerificationFactory()
+ .createFromOdElement(
+ XmlUtils.getOdPbundleWithName(
+ safetyLabelsEle,
+ XmlUtils.OD_NAME_THIRD_PARTY_VERIFICATION,
+ requiredOdEles));
+ return new SafetyLabels(dataLabels, securityLabels, thirdPartyVerification);
}
}
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SecurityLabels.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SecurityLabels.java
index 48643ba0e3ab..ccb84451c96f 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SecurityLabels.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SecurityLabels.java
@@ -21,8 +21,6 @@ import com.android.asllib.util.XmlUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
-import java.util.List;
-
/** Security Labels representation */
public class SecurityLabels implements AslMarshallable {
@@ -35,8 +33,7 @@ public class SecurityLabels implements AslMarshallable {
}
/** Creates an on-device DOM element from the {@link SecurityLabels}. */
- @Override
- public List<Element> toOdDomElements(Document doc) {
+ public Element toOdDomElement(Document doc) {
Element ele = XmlUtils.createPbundleEleWithName(doc, XmlUtils.OD_NAME_SECURITY_LABELS);
if (mIsDataDeletable != null) {
ele.appendChild(
@@ -48,12 +45,11 @@ public class SecurityLabels implements AslMarshallable {
XmlUtils.createOdBooleanEle(
doc, XmlUtils.OD_NAME_IS_DATA_ENCRYPTED, mIsDataEncrypted));
}
- return XmlUtils.listOf(ele);
+ return ele;
}
/** Creates the human-readable DOM elements from the AslMarshallable Java Object. */
- @Override
- public List<Element> toHrDomElements(Document doc) {
+ public Element toHrDomElement(Document doc) {
Element ele = doc.createElement(XmlUtils.HR_TAG_SECURITY_LABELS);
if (mIsDataDeletable != null) {
ele.setAttribute(XmlUtils.HR_ATTR_IS_DATA_DELETABLE, String.valueOf(mIsDataDeletable));
@@ -61,6 +57,6 @@ public class SecurityLabels implements AslMarshallable {
if (mIsDataEncrypted != null) {
ele.setAttribute(XmlUtils.HR_ATTR_IS_DATA_ENCRYPTED, String.valueOf(mIsDataEncrypted));
}
- return XmlUtils.listOf(ele);
+ return ele;
}
}
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SecurityLabelsFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SecurityLabelsFactory.java
index 525a80388261..da98a4291b4a 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SecurityLabelsFactory.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SecurityLabelsFactory.java
@@ -22,15 +22,10 @@ import com.android.asllib.util.XmlUtils;
import org.w3c.dom.Element;
-import java.util.List;
-
public class SecurityLabelsFactory implements AslMarshallableFactory<SecurityLabels> {
/** Creates a {@link SecurityLabels} from the human-readable DOM element. */
- @Override
- public SecurityLabels createFromHrElements(List<Element> elements)
- throws MalformedXmlException {
- Element ele = XmlUtils.getSingleElement(elements);
+ public SecurityLabels createFromHrElement(Element ele) throws MalformedXmlException {
if (ele == null) {
AslgenUtil.logI("No SecurityLabels found in hr format.");
return null;
@@ -43,10 +38,7 @@ public class SecurityLabelsFactory implements AslMarshallableFactory<SecurityLab
}
/** Creates an {@link AslMarshallableFactory} from on-device DOM elements */
- @Override
- public SecurityLabels createFromOdElements(List<Element> elements)
- throws MalformedXmlException {
- Element ele = XmlUtils.getSingleElement(elements);
+ public SecurityLabels createFromOdElement(Element ele) throws MalformedXmlException {
if (ele == null) {
AslgenUtil.logI("No SecurityLabels found in od format.");
return null;
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SystemAppSafetyLabel.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SystemAppSafetyLabel.java
index 242e7be66d76..10d6e1aaac7d 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SystemAppSafetyLabel.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SystemAppSafetyLabel.java
@@ -21,34 +21,43 @@ import com.android.asllib.util.XmlUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
-import java.util.List;
-
/** Safety Label representation containing zero or more {@link DataCategory} for data shared */
public class SystemAppSafetyLabel implements AslMarshallable {
+ private final String mUrl;
private final Boolean mDeclaration;
- public SystemAppSafetyLabel(Boolean d) {
+ public SystemAppSafetyLabel(String url, Boolean d) {
this.mDeclaration = d;
+ this.mUrl = null;
}
/** Creates an on-device DOM element from the {@link SystemAppSafetyLabel}. */
- @Override
- public List<Element> toOdDomElements(Document doc) {
+ public Element toOdDomElement(Document doc) {
Element systemAppSafetyLabelEle =
XmlUtils.createPbundleEleWithName(doc, XmlUtils.OD_NAME_SYSTEM_APP_SAFETY_LABEL);
- systemAppSafetyLabelEle.appendChild(
- XmlUtils.createOdBooleanEle(doc, XmlUtils.OD_NAME_DECLARATION, mDeclaration));
- return XmlUtils.listOf(systemAppSafetyLabelEle);
+ if (mUrl != null) {
+ systemAppSafetyLabelEle.appendChild(
+ XmlUtils.createOdStringEle(doc, XmlUtils.OD_NAME_URL, mUrl));
+ }
+ if (mDeclaration != null) {
+ systemAppSafetyLabelEle.appendChild(
+ XmlUtils.createOdBooleanEle(doc, XmlUtils.OD_NAME_DECLARATION, mDeclaration));
+ }
+ return systemAppSafetyLabelEle;
}
/** Creates the human-readable DOM elements from the AslMarshallable Java Object. */
- @Override
- public List<Element> toHrDomElements(Document doc) {
+ public Element toHrDomElement(Document doc) {
Element systemAppSafetyLabelEle =
doc.createElement(XmlUtils.HR_TAG_SYSTEM_APP_SAFETY_LABEL);
- XmlUtils.maybeSetHrBoolAttr(
- systemAppSafetyLabelEle, XmlUtils.HR_ATTR_DECLARATION, mDeclaration);
- return XmlUtils.listOf(systemAppSafetyLabelEle);
+ if (mUrl != null) {
+ systemAppSafetyLabelEle.setAttribute(XmlUtils.HR_ATTR_URL, mUrl);
+ }
+ if (mDeclaration != null) {
+ systemAppSafetyLabelEle.setAttribute(
+ XmlUtils.HR_ATTR_DECLARATION, String.valueOf(mDeclaration));
+ }
+ return systemAppSafetyLabelEle;
}
}
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SystemAppSafetyLabelFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SystemAppSafetyLabelFactory.java
index 7f4aa7a3b690..971ae9296eb8 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SystemAppSafetyLabelFactory.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SystemAppSafetyLabelFactory.java
@@ -16,42 +16,77 @@
package com.android.asllib.marshallable;
-import com.android.asllib.util.AslgenUtil;
import com.android.asllib.util.MalformedXmlException;
import com.android.asllib.util.XmlUtils;
import org.w3c.dom.Element;
-import java.util.List;
+import java.util.Map;
+import java.util.Set;
public class SystemAppSafetyLabelFactory implements AslMarshallableFactory<SystemAppSafetyLabel> {
+ private final Map<Long, Set<String>> mRecognizedHrAttrs =
+ Map.ofEntries(
+ Map.entry(1L, Set.of(XmlUtils.HR_ATTR_URL)),
+ Map.entry(2L, Set.of(XmlUtils.HR_ATTR_DECLARATION)));
+ private final Map<Long, Set<String>> mRequiredHrAttrs =
+ Map.ofEntries(
+ Map.entry(1L, Set.of(XmlUtils.HR_ATTR_URL)),
+ Map.entry(2L, Set.of(XmlUtils.HR_ATTR_DECLARATION)));
+ private final Map<Long, Set<String>> mRecognizedHrEles = Map.ofEntries(Map.entry(1L, Set.of()));
+ private final Map<Long, Set<String>> mRecognizedOdEleNames =
+ Map.ofEntries(
+ Map.entry(1L, Set.of(XmlUtils.OD_NAME_URL)),
+ Map.entry(2L, Set.of(XmlUtils.OD_NAME_DECLARATION)));
+ private final Map<Long, Set<String>> mRequiredOdEleNames =
+ Map.ofEntries(
+ Map.entry(1L, Set.of(XmlUtils.OD_NAME_URL)),
+ Map.entry(2L, Set.of(XmlUtils.OD_NAME_DECLARATION)));
/** Creates a {@link SystemAppSafetyLabel} from the human-readable DOM element. */
- @Override
- public SystemAppSafetyLabel createFromHrElements(List<Element> elements)
+ public SystemAppSafetyLabel createFromHrElement(Element systemAppSafetyLabelEle, long version)
throws MalformedXmlException {
- Element systemAppSafetyLabelEle = XmlUtils.getSingleElement(elements);
if (systemAppSafetyLabelEle == null) {
- AslgenUtil.logI("No SystemAppSafetyLabel found in hr format.");
return null;
}
+ XmlUtils.throwIfExtraneousAttributes(
+ systemAppSafetyLabelEle,
+ XmlUtils.getMostRecentVersion(mRecognizedHrAttrs, version));
+ XmlUtils.throwIfExtraneousChildrenHr(
+ systemAppSafetyLabelEle, XmlUtils.getMostRecentVersion(mRecognizedHrEles, version));
+ String url =
+ XmlUtils.getStringAttr(
+ systemAppSafetyLabelEle,
+ XmlUtils.HR_ATTR_URL,
+ XmlUtils.getMostRecentVersion(mRequiredHrAttrs, version));
Boolean declaration =
- XmlUtils.getBoolAttr(systemAppSafetyLabelEle, XmlUtils.HR_ATTR_DECLARATION, true);
- return new SystemAppSafetyLabel(declaration);
+ XmlUtils.getBoolAttr(
+ systemAppSafetyLabelEle,
+ XmlUtils.HR_ATTR_DECLARATION,
+ XmlUtils.getMostRecentVersion(mRequiredHrAttrs, version));
+ return new SystemAppSafetyLabel(url, declaration);
}
/** Creates an {@link AslMarshallableFactory} from on-device DOM elements */
- @Override
- public SystemAppSafetyLabel createFromOdElements(List<Element> elements)
+ public SystemAppSafetyLabel createFromOdElement(Element systemAppSafetyLabelEle, long version)
throws MalformedXmlException {
- Element systemAppSafetyLabelEle = XmlUtils.getSingleElement(elements);
if (systemAppSafetyLabelEle == null) {
- AslgenUtil.logI("No SystemAppSafetyLabel found in od format.");
return null;
}
+ XmlUtils.throwIfExtraneousChildrenOd(
+ systemAppSafetyLabelEle,
+ XmlUtils.getMostRecentVersion(mRecognizedOdEleNames, version));
+ String url =
+ XmlUtils.getOdStringEle(
+ systemAppSafetyLabelEle,
+ XmlUtils.OD_NAME_URL,
+ XmlUtils.getMostRecentVersion(mRequiredOdEleNames, version));
Boolean declaration =
- XmlUtils.getOdBoolEle(systemAppSafetyLabelEle, XmlUtils.OD_NAME_DECLARATION, true);
- return new SystemAppSafetyLabel(declaration);
+ XmlUtils.getOdBoolEle(
+ systemAppSafetyLabelEle,
+ XmlUtils.OD_NAME_DECLARATION,
+ XmlUtils.getMostRecentVersion(mRequiredOdEleNames, version));
+ return new SystemAppSafetyLabel(url, declaration);
}
}
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/ThirdPartyVerification.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/ThirdPartyVerification.java
index d74f3f062513..151cdb1e2f51 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/ThirdPartyVerification.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/ThirdPartyVerification.java
@@ -21,8 +21,6 @@ import com.android.asllib.util.XmlUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
-import java.util.List;
-
/** ThirdPartyVerification representation. */
public class ThirdPartyVerification implements AslMarshallable {
@@ -33,19 +31,17 @@ public class ThirdPartyVerification implements AslMarshallable {
}
/** Creates an on-device DOM element from the {@link ThirdPartyVerification}. */
- @Override
- public List<Element> toOdDomElements(Document doc) {
+ public Element toOdDomElement(Document doc) {
Element ele =
XmlUtils.createPbundleEleWithName(doc, XmlUtils.OD_NAME_THIRD_PARTY_VERIFICATION);
ele.appendChild(XmlUtils.createOdStringEle(doc, XmlUtils.OD_NAME_URL, mUrl));
- return XmlUtils.listOf(ele);
+ return ele;
}
/** Creates the human-readable DOM elements from the AslMarshallable Java Object. */
- @Override
- public List<Element> toHrDomElements(Document doc) {
+ public Element toHrDomElement(Document doc) {
Element ele = doc.createElement(XmlUtils.HR_TAG_THIRD_PARTY_VERIFICATION);
ele.setAttribute(XmlUtils.HR_ATTR_URL, mUrl);
- return XmlUtils.listOf(ele);
+ return ele;
}
}
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/ThirdPartyVerificationFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/ThirdPartyVerificationFactory.java
index 197e7aa77743..f229ad6c861f 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/ThirdPartyVerificationFactory.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/ThirdPartyVerificationFactory.java
@@ -22,16 +22,11 @@ import com.android.asllib.util.XmlUtils;
import org.w3c.dom.Element;
-import java.util.List;
-
public class ThirdPartyVerificationFactory
implements AslMarshallableFactory<ThirdPartyVerification> {
/** Creates a {@link ThirdPartyVerification} from the human-readable DOM element. */
- @Override
- public ThirdPartyVerification createFromHrElements(List<Element> elements)
- throws MalformedXmlException {
- Element ele = XmlUtils.getSingleElement(elements);
+ public ThirdPartyVerification createFromHrElement(Element ele) throws MalformedXmlException {
if (ele == null) {
AslgenUtil.logI("No ThirdPartyVerification found in hr format.");
return null;
@@ -42,10 +37,7 @@ public class ThirdPartyVerificationFactory
}
/** Creates an {@link AslMarshallableFactory} from on-device DOM elements */
- @Override
- public ThirdPartyVerification createFromOdElements(List<Element> elements)
- throws MalformedXmlException {
- Element ele = XmlUtils.getSingleElement(elements);
+ public ThirdPartyVerification createFromOdElement(Element ele) throws MalformedXmlException {
if (ele == null) {
AslgenUtil.logI("No ThirdPartyVerification found in od format.");
return null;
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/TransparencyInfo.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/TransparencyInfo.java
index 9f789f0b9c1c..f24e6bf58efb 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/TransparencyInfo.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/TransparencyInfo.java
@@ -21,39 +21,39 @@ import com.android.asllib.util.XmlUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
-import java.util.List;
-
/** TransparencyInfo representation containing {@link AppInfo} */
public class TransparencyInfo implements AslMarshallable {
+
+ private final DeveloperInfo mDeveloperInfo;
private final AppInfo mAppInfo;
- public TransparencyInfo(AppInfo appInfo) {
+ public TransparencyInfo(DeveloperInfo developerInfo, AppInfo appInfo) {
+ this.mDeveloperInfo = developerInfo;
this.mAppInfo = appInfo;
}
- /** Gets the {@link AppInfo} of the {@link TransparencyInfo}. */
- public AppInfo getAppInfo() {
- return mAppInfo;
- }
-
/** Creates an on-device DOM element from the {@link TransparencyInfo}. */
- @Override
- public List<Element> toOdDomElements(Document doc) {
+ public Element toOdDomElement(Document doc) {
Element transparencyInfoEle =
XmlUtils.createPbundleEleWithName(doc, XmlUtils.OD_NAME_TRANSPARENCY_INFO);
+ if (mDeveloperInfo != null) {
+ transparencyInfoEle.appendChild(mDeveloperInfo.toOdDomElement(doc));
+ }
if (mAppInfo != null) {
- XmlUtils.appendChildren(transparencyInfoEle, mAppInfo.toOdDomElements(doc));
+ transparencyInfoEle.appendChild(mAppInfo.toOdDomElement(doc));
}
- return XmlUtils.listOf(transparencyInfoEle);
+ return transparencyInfoEle;
}
/** Creates the human-readable DOM elements from the AslMarshallable Java Object. */
- @Override
- public List<Element> toHrDomElements(Document doc) {
+ public Element toHrDomElement(Document doc) {
Element transparencyInfoEle = doc.createElement(XmlUtils.HR_TAG_TRANSPARENCY_INFO);
+ if (mDeveloperInfo != null) {
+ transparencyInfoEle.appendChild(mDeveloperInfo.toHrDomElement(doc));
+ }
if (mAppInfo != null) {
- XmlUtils.appendChildren(transparencyInfoEle, mAppInfo.toHrDomElements(doc));
+ transparencyInfoEle.appendChild(mAppInfo.toHrDomElement(doc));
}
- return XmlUtils.listOf(transparencyInfoEle);
+ return transparencyInfoEle;
}
}
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/TransparencyInfoFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/TransparencyInfoFactory.java
index 40f2872e4380..9e98941e0d6d 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/TransparencyInfoFactory.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/TransparencyInfoFactory.java
@@ -16,47 +16,84 @@
package com.android.asllib.marshallable;
-import com.android.asllib.util.AslgenUtil;
import com.android.asllib.util.MalformedXmlException;
import com.android.asllib.util.XmlUtils;
import org.w3c.dom.Element;
-import java.util.List;
+import java.util.Map;
+import java.util.Set;
public class TransparencyInfoFactory implements AslMarshallableFactory<TransparencyInfo> {
+ private final Map<Long, Set<String>> mRecognizedHrAttrs =
+ Map.ofEntries(Map.entry(1L, Set.of()));
+ private final Map<Long, Set<String>> mRequiredHrAttrs = Map.ofEntries(Map.entry(1L, Set.of()));
+ private final Map<Long, Set<String>> mRecognizedHrEles =
+ Map.ofEntries(
+ Map.entry(1L, Set.of(XmlUtils.HR_TAG_DEVELOPER_INFO, XmlUtils.HR_TAG_APP_INFO)),
+ Map.entry(2L, Set.of(XmlUtils.HR_TAG_APP_INFO)));
+ private final Map<Long, Set<String>> mRequiredHrEles =
+ Map.ofEntries(Map.entry(1L, Set.of()), Map.entry(2L, Set.of(XmlUtils.HR_TAG_APP_INFO)));
+ private final Map<Long, Set<String>> mRecognizedOdEleNames =
+ Map.ofEntries(
+ Map.entry(
+ 1L, Set.of(XmlUtils.OD_NAME_DEVELOPER_INFO, XmlUtils.OD_NAME_APP_INFO)),
+ Map.entry(2L, Set.of(XmlUtils.OD_NAME_APP_INFO)));
+ private final Map<Long, Set<String>> mRequiredOdEles =
+ Map.ofEntries(
+ Map.entry(1L, Set.of()), Map.entry(2L, Set.of(XmlUtils.OD_NAME_APP_INFO)));
/** Creates a {@link TransparencyInfo} from the human-readable DOM element. */
- @Override
- public TransparencyInfo createFromHrElements(List<Element> elements)
+ public TransparencyInfo createFromHrElement(Element transparencyInfoEle, long version)
throws MalformedXmlException {
- Element transparencyInfoEle = XmlUtils.getSingleElement(elements);
if (transparencyInfoEle == null) {
- AslgenUtil.logI("No TransparencyInfo found in hr format.");
return null;
}
+ XmlUtils.throwIfExtraneousAttributes(
+ transparencyInfoEle, XmlUtils.getMostRecentVersion(mRecognizedHrAttrs, version));
+ XmlUtils.throwIfExtraneousChildrenHr(
+ transparencyInfoEle, XmlUtils.getMostRecentVersion(mRecognizedHrEles, version));
+ Element developerInfoEle =
+ XmlUtils.getSingleChildElement(
+ transparencyInfoEle,
+ XmlUtils.HR_TAG_DEVELOPER_INFO,
+ XmlUtils.getMostRecentVersion(mRequiredHrEles, version));
+ DeveloperInfo developerInfo =
+ new DeveloperInfoFactory().createFromHrElement(developerInfoEle);
Element appInfoEle =
- XmlUtils.getSingleChildElement(transparencyInfoEle, XmlUtils.HR_TAG_APP_INFO, true);
- AppInfo appInfo = new AppInfoFactory().createFromHrElements(XmlUtils.listOf(appInfoEle));
+ XmlUtils.getSingleChildElement(
+ transparencyInfoEle,
+ XmlUtils.HR_TAG_APP_INFO,
+ XmlUtils.getMostRecentVersion(mRequiredHrEles, version));
+ AppInfo appInfo = new AppInfoFactory().createFromHrElement(appInfoEle, version);
- return new TransparencyInfo(appInfo);
+ return new TransparencyInfo(developerInfo, appInfo);
}
/** Creates an {@link AslMarshallableFactory} from on-device DOM elements */
- @Override
- public TransparencyInfo createFromOdElements(List<Element> elements)
+ public TransparencyInfo createFromOdElement(Element transparencyInfoEle, long version)
throws MalformedXmlException {
- Element transparencyInfoEle = XmlUtils.getSingleElement(elements);
if (transparencyInfoEle == null) {
- AslgenUtil.logI("No TransparencyInfo found in od format.");
return null;
}
+ XmlUtils.throwIfExtraneousChildrenOd(
+ transparencyInfoEle, XmlUtils.getMostRecentVersion(mRecognizedOdEleNames, version));
+ Element developerInfoEle =
+ XmlUtils.getOdPbundleWithName(
+ transparencyInfoEle,
+ XmlUtils.OD_NAME_DEVELOPER_INFO,
+ XmlUtils.getMostRecentVersion(mRequiredOdEles, version));
+ DeveloperInfo developerInfo =
+ new DeveloperInfoFactory().createFromOdElement(developerInfoEle);
Element appInfoEle =
- XmlUtils.getOdPbundleWithName(transparencyInfoEle, XmlUtils.OD_NAME_APP_INFO, true);
- AppInfo appInfo = new AppInfoFactory().createFromOdElements(XmlUtils.listOf(appInfoEle));
+ XmlUtils.getOdPbundleWithName(
+ transparencyInfoEle,
+ XmlUtils.OD_NAME_APP_INFO,
+ XmlUtils.getMostRecentVersion(mRequiredOdEles, version));
+ AppInfo appInfo = new AppInfoFactory().createFromOdElement(appInfoEle, version);
- return new TransparencyInfo(appInfo);
+ return new TransparencyInfo(developerInfo, appInfo);
}
}
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/util/XmlUtils.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/util/XmlUtils.java
index 2c1517bdf8ab..52c4390036f3 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/util/XmlUtils.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/util/XmlUtils.java
@@ -25,6 +25,8 @@ import org.w3c.dom.NodeList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.Map;
+import java.util.Set;
import java.util.stream.Collectors;
public class XmlUtils {
@@ -70,6 +72,8 @@ public class XmlUtils {
public static final String HR_ATTR_ADS_FINGERPRINTING = "adsFingerprinting";
public static final String HR_ATTR_SECURITY_FINGERPRINTING = "securityFingerprinting";
public static final String HR_ATTR_PRIVACY_POLICY = "privacyPolicy";
+ public static final String HR_ATTR_DEVELOPER_ID = "developerId";
+ public static final String HR_ATTR_APPLICATION_ID = "applicationId";
public static final String HR_ATTR_SECURITY_ENDPOINTS = "securityEndpoints";
public static final String HR_TAG_FIRST_PARTY_ENDPOINTS = "first-party-endpoints";
public static final String HR_TAG_SERVICE_PROVIDER_ENDPOINTS = "service-provider-endpoints";
@@ -102,10 +106,12 @@ public class XmlUtils {
public static final String OD_NAME_CONTAINS_ADS = "contains_ads";
public static final String OD_NAME_OBEY_APS = "obey_aps";
public static final String OD_NAME_APS_COMPLIANT = "aps_compliant";
+ public static final String OD_NAME_DEVELOPER_ID = "developer_id";
+ public static final String OD_NAME_APPLICATION_ID = "application_id";
public static final String OD_NAME_ADS_FINGERPRINTING = "ads_fingerprinting";
public static final String OD_NAME_SECURITY_FINGERPRINTING = "security_fingerprinting";
public static final String OD_NAME_PRIVACY_POLICY = "privacy_policy";
- public static final String OD_NAME_SECURITY_ENDPOINT = "security_endpoints";
+ public static final String OD_NAME_SECURITY_ENDPOINTS = "security_endpoints";
public static final String OD_NAME_FIRST_PARTY_ENDPOINTS = "first_party_endpoints";
public static final String OD_NAME_SERVICE_PROVIDER_ENDPOINTS = "service_provider_endpoints";
public static final String OD_NAME_CATEGORY = "category";
@@ -140,6 +146,15 @@ public class XmlUtils {
/**
* Gets the single {@link Element} within {@param parentEle} and having the {@param tagName}.
*/
+ public static Element getSingleChildElement(
+ Node parentEle, String tagName, Set<String> requiredStrings)
+ throws MalformedXmlException {
+ return getSingleChildElement(parentEle, tagName, requiredStrings.contains(tagName));
+ }
+
+ /**
+ * Gets the single {@link Element} within {@param parentEle} and having the {@param tagName}.
+ */
public static Element getSingleChildElement(Node parentEle, String tagName, boolean required)
throws MalformedXmlException {
String parentTagNameForErrorMsg =
@@ -287,19 +302,36 @@ public class XmlUtils {
}
/** Gets a pipeline-split attribute. */
+ public static List<String> getPipelineSplitAttr(
+ Element ele, String attrName, Set<String> requiredNames) throws MalformedXmlException {
+ return getPipelineSplitAttr(ele, attrName, requiredNames.contains(attrName));
+ }
+
+ /** Gets a pipeline-split attribute. */
public static List<String> getPipelineSplitAttr(Element ele, String attrName, boolean required)
throws MalformedXmlException {
List<String> list =
Arrays.stream(ele.getAttribute(attrName).split("\\|")).collect(Collectors.toList());
- if ((list.isEmpty() || list.get(0).isEmpty()) && required) {
- throw new MalformedXmlException(
- String.format(
- "Delimited string %s was required but missing, in %s.",
- attrName, ele.getTagName()));
+ if ((list.isEmpty() || list.get(0).isEmpty())) {
+ if (required) {
+ throw new MalformedXmlException(
+ String.format(
+ "Delimited string %s was required but missing, in %s.",
+ attrName, ele.getTagName()));
+ }
+ return null;
}
return list;
}
+ /**
+ * Gets the single {@link Element} within {@param parentEle} and having the {@param tagName}.
+ */
+ public static Boolean getBoolAttr(Element ele, String attrName, Set<String> requiredStrings)
+ throws MalformedXmlException {
+ return getBoolAttr(ele, attrName, requiredStrings.contains(attrName));
+ }
+
/** Gets a Boolean attribute. */
public static Boolean getBoolAttr(Element ele, String attrName, boolean required)
throws MalformedXmlException {
@@ -314,6 +346,12 @@ public class XmlUtils {
}
/** Gets a Boolean attribute. */
+ public static Boolean getOdBoolEle(Element ele, String nameName, Set<String> requiredNames)
+ throws MalformedXmlException {
+ return getOdBoolEle(ele, nameName, requiredNames.contains(nameName));
+ }
+
+ /** Gets a Boolean attribute. */
public static Boolean getOdBoolEle(Element ele, String nameName, boolean required)
throws MalformedXmlException {
List<Element> boolEles =
@@ -376,6 +414,12 @@ public class XmlUtils {
}
/** Gets an on-device String attribute. */
+ public static String getOdStringEle(Element ele, String nameName, Set<String> requiredNames)
+ throws MalformedXmlException {
+ return getOdStringEle(ele, nameName, requiredNames.contains(nameName));
+ }
+
+ /** Gets an on-device String attribute. */
public static String getOdStringEle(Element ele, String nameName, boolean required)
throws MalformedXmlException {
List<Element> eles =
@@ -404,6 +448,13 @@ public class XmlUtils {
}
/** Gets a OD Pbundle Element attribute with the specified name. */
+ public static Element getOdPbundleWithName(
+ Element ele, String nameName, Set<String> requiredStrings)
+ throws MalformedXmlException {
+ return getOdPbundleWithName(ele, nameName, requiredStrings.contains(nameName));
+ }
+
+ /** Gets a OD Pbundle Element attribute with the specified name. */
public static Element getOdPbundleWithName(Element ele, String nameName, boolean required)
throws MalformedXmlException {
List<Element> eles =
@@ -425,6 +476,14 @@ public class XmlUtils {
return eles.get(0);
}
+ /**
+ * Gets the single {@link Element} within {@param parentEle} and having the {@param tagName}.
+ */
+ public static String getStringAttr(Element ele, String attrName, Set<String> requiredStrings)
+ throws MalformedXmlException {
+ return getStringAttr(ele, attrName, requiredStrings.contains(attrName));
+ }
+
/** Gets a required String attribute. */
public static String getStringAttr(Element ele, String attrName) throws MalformedXmlException {
return getStringAttr(ele, attrName, true);
@@ -476,6 +535,13 @@ public class XmlUtils {
/** Gets human-readable style String array. */
public static List<String> getHrItemsAsStrings(
+ Element parent, String elementName, Set<String> requiredNames)
+ throws MalformedXmlException {
+ return getHrItemsAsStrings(parent, elementName, requiredNames.contains(elementName));
+ }
+
+ /** Gets human-readable style String array. */
+ public static List<String> getHrItemsAsStrings(
Element parent, String elementName, boolean required) throws MalformedXmlException {
List<Element> arrayEles = XmlUtils.getChildrenByTagName(parent, elementName);
@@ -501,6 +567,12 @@ public class XmlUtils {
}
/** Gets on-device style String array. */
+ public static List<String> getOdStringArray(
+ Element ele, String nameName, Set<String> requiredNames) throws MalformedXmlException {
+ return getOdStringArray(ele, nameName, requiredNames.contains(nameName));
+ }
+
+ /** Gets on-device style String array. */
public static List<String> getOdStringArray(Element ele, String nameName, boolean required)
throws MalformedXmlException {
List<Element> arrayEles =
@@ -530,6 +602,73 @@ public class XmlUtils {
return strs;
}
+ /** Throws if extraneous child elements detected */
+ public static void throwIfExtraneousChildrenHr(Element ele, Set<String> expectedChildNames)
+ throws MalformedXmlException {
+ var childEles = XmlUtils.asElementList(ele.getChildNodes());
+ List<Element> extraneousEles =
+ childEles.stream()
+ .filter(e -> !expectedChildNames.contains(e.getTagName()))
+ .collect(Collectors.toList());
+ if (!extraneousEles.isEmpty()) {
+ throw new MalformedXmlException(
+ String.format(
+ "Unexpected element(s) %s in %s.",
+ extraneousEles.stream()
+ .map(Element::getTagName)
+ .collect(Collectors.joining(",")),
+ ele.getTagName()));
+ }
+ }
+
+ /** Throws if extraneous child elements detected */
+ public static void throwIfExtraneousChildrenOd(Element ele, Set<String> expectedChildNames)
+ throws MalformedXmlException {
+ var allChildElements = XmlUtils.asElementList(ele.getChildNodes());
+ List<Element> extraneousEles =
+ allChildElements.stream()
+ .filter(
+ e ->
+ !e.getAttribute(XmlUtils.OD_ATTR_NAME).isEmpty()
+ && !expectedChildNames.contains(
+ e.getAttribute(XmlUtils.OD_ATTR_NAME)))
+ .collect(Collectors.toList());
+ if (!extraneousEles.isEmpty()) {
+ throw new MalformedXmlException(
+ String.format(
+ "Unexpected element(s) in %s: %s",
+ ele.getTagName(),
+ extraneousEles.stream()
+ .map(
+ e ->
+ String.format(
+ "%s name=%s",
+ e.getTagName(),
+ e.getAttribute(XmlUtils.OD_ATTR_NAME)))
+ .collect(Collectors.joining(","))));
+ }
+ }
+
+ /** Throws if extraneous attributes detected */
+ public static void throwIfExtraneousAttributes(Element ele, Set<String> expectedAttrNames)
+ throws MalformedXmlException {
+ var attrs = ele.getAttributes();
+ List<String> attrNames = new ArrayList<>();
+ for (int i = 0; i < attrs.getLength(); i++) {
+ attrNames.add(attrs.item(i).getNodeName());
+ }
+ List<String> extraneousAttrs =
+ attrNames.stream()
+ .filter(s -> !expectedAttrNames.contains(s))
+ .collect(Collectors.toList());
+ if (!extraneousAttrs.isEmpty()) {
+ throw new MalformedXmlException(
+ String.format(
+ "Unexpected attr(s) %s in %s.",
+ String.join(",", extraneousAttrs), ele.getTagName()));
+ }
+ }
+
/**
* Utility method for making a List from one element, to support easier refactoring if needed.
* For example, List.of() doesn't support null elements.
@@ -537,4 +676,26 @@ public class XmlUtils {
public static List<Element> listOf(Element e) {
return Arrays.asList(e);
}
+
+ /**
+ * Gets the most recent version of fields in the mapping. This way when a new version is
+ * released, we only need to update the mappings that were modified. The rest will fall back to
+ * the most recent previous version.
+ */
+ public static Set<String> getMostRecentVersion(
+ Map<Long, Set<String>> versionToFieldsMapping, long version)
+ throws MalformedXmlException {
+ long bestVersion = 0;
+ Set<String> bestSet = null;
+ for (Map.Entry<Long, Set<String>> entry : versionToFieldsMapping.entrySet()) {
+ if (entry.getKey() > bestVersion && entry.getKey() <= version) {
+ bestVersion = entry.getKey();
+ bestSet = entry.getValue();
+ }
+ }
+ if (bestSet == null) {
+ throw new MalformedXmlException("Unexpected version: " + version);
+ }
+ return bestSet;
+ }
}
diff --git a/tools/app_metadata_bundles/src/test/java/com/android/asllib/AslgenTests.java b/tools/app_metadata_bundles/src/test/java/com/android/asllib/AslgenTests.java
index 5d1d45a9a29b..262f76d52c90 100644
--- a/tools/app_metadata_bundles/src/test/java/com/android/asllib/AslgenTests.java
+++ b/tools/app_metadata_bundles/src/test/java/com/android/asllib/AslgenTests.java
@@ -41,6 +41,18 @@ public class AslgenTests {
/** Logic for setting up tests (empty if not yet needed). */
public static void main(String[] params) throws Exception {}
+ @Test
+ public void testValidOd() throws Exception {
+ System.out.println("start testing valid od.");
+ Path odPath = Paths.get(VALID_MAPPINGS_PATH, "general-v1", OD_XML_FILENAME);
+ InputStream odStream = getClass().getClassLoader().getResourceAsStream(odPath.toString());
+ String odContents =
+ TestUtils.getFormattedXml(
+ new String(odStream.readAllBytes(), StandardCharsets.UTF_8), false);
+ AndroidSafetyLabel unusedAsl =
+ AslConverter.readFromString(odContents, AslConverter.Format.ON_DEVICE);
+ }
+
/** Tests valid mappings between HR and OD. */
@Test
public void testValidMappings() throws Exception {
diff --git a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/AndroidSafetyLabelTest.java b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/AndroidSafetyLabelTest.java
index 61a78232801c..283ccbc44791 100644
--- a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/AndroidSafetyLabelTest.java
+++ b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/AndroidSafetyLabelTest.java
@@ -16,12 +16,18 @@
package com.android.asllib.marshallable;
+import static org.junit.Assert.assertThrows;
+
import com.android.asllib.testutils.TestUtils;
+import com.android.asllib.util.MalformedXmlException;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+import org.w3c.dom.Element;
+
+import java.nio.file.Paths;
@RunWith(JUnit4.class)
public class AndroidSafetyLabelTest {
@@ -66,47 +72,49 @@ public class AndroidSafetyLabelTest {
testOdToHrAndroidSafetyLabel(WITH_SAFETY_LABELS_FILE_NAME);
}
- /** Test for android safety label with system app safety label. */
- @Test
- public void testAndroidSafetyLabelWithSystemAppSafetyLabel() throws Exception {
- System.out.println("starting testAndroidSafetyLabelWithSystemAppSafetyLabel.");
- testHrToOdAndroidSafetyLabel(WITH_SYSTEM_APP_SAFETY_LABEL_FILE_NAME);
- testOdToHrAndroidSafetyLabel(WITH_SYSTEM_APP_SAFETY_LABEL_FILE_NAME);
- }
-
- /** Test for android safety label with transparency info. */
- @Test
- public void testAndroidSafetyLabelWithTransparencyInfo() throws Exception {
- System.out.println("starting testAndroidSafetyLabelWithTransparencyInfo.");
- testHrToOdAndroidSafetyLabel(WITH_TRANSPARENCY_INFO_FILE_NAME);
- testOdToHrAndroidSafetyLabel(WITH_TRANSPARENCY_INFO_FILE_NAME);
- }
-
private void hrToOdExpectException(String fileName) {
- TestUtils.hrToOdExpectException(
- new AndroidSafetyLabelFactory(), ANDROID_SAFETY_LABEL_HR_PATH, fileName);
+ assertThrows(
+ MalformedXmlException.class,
+ () -> {
+ new AndroidSafetyLabelFactory()
+ .createFromHrElement(
+ TestUtils.getElementFromResource(
+ Paths.get(ANDROID_SAFETY_LABEL_HR_PATH, fileName)));
+ });
}
private void odToHrExpectException(String fileName) {
- TestUtils.odToHrExpectException(
- new AndroidSafetyLabelFactory(), ANDROID_SAFETY_LABEL_OD_PATH, fileName);
+ assertThrows(
+ MalformedXmlException.class,
+ () -> {
+ new AndroidSafetyLabelFactory()
+ .createFromOdElement(
+ TestUtils.getElementFromResource(
+ Paths.get(ANDROID_SAFETY_LABEL_OD_PATH, fileName)));
+ });
}
private void testHrToOdAndroidSafetyLabel(String fileName) throws Exception {
- TestUtils.testHrToOd(
- TestUtils.document(),
- new AndroidSafetyLabelFactory(),
- ANDROID_SAFETY_LABEL_HR_PATH,
- ANDROID_SAFETY_LABEL_OD_PATH,
- fileName);
+ var doc = TestUtils.document();
+ AndroidSafetyLabel asl =
+ new AndroidSafetyLabelFactory()
+ .createFromHrElement(
+ TestUtils.getElementFromResource(
+ Paths.get(ANDROID_SAFETY_LABEL_HR_PATH, fileName)));
+ Element aslEle = asl.toOdDomElement(doc);
+ doc.appendChild(aslEle);
+ TestUtils.testFormatToFormat(doc, Paths.get(ANDROID_SAFETY_LABEL_OD_PATH, fileName));
}
private void testOdToHrAndroidSafetyLabel(String fileName) throws Exception {
- TestUtils.testOdToHr(
- TestUtils.document(),
- new AndroidSafetyLabelFactory(),
- ANDROID_SAFETY_LABEL_OD_PATH,
- ANDROID_SAFETY_LABEL_HR_PATH,
- fileName);
+ var doc = TestUtils.document();
+ AndroidSafetyLabel asl =
+ new AndroidSafetyLabelFactory()
+ .createFromOdElement(
+ TestUtils.getElementFromResource(
+ Paths.get(ANDROID_SAFETY_LABEL_OD_PATH, fileName)));
+ Element aslEle = asl.toHrDomElement(doc);
+ doc.appendChild(aslEle);
+ TestUtils.testFormatToFormat(doc, Paths.get(ANDROID_SAFETY_LABEL_HR_PATH, fileName));
}
}
diff --git a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/AppInfoTest.java b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/AppInfoTest.java
index d823c482adfe..7806061f00bb 100644
--- a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/AppInfoTest.java
+++ b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/AppInfoTest.java
@@ -26,12 +26,14 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+import org.w3c.dom.Element;
import java.nio.file.Paths;
import java.util.List;
@RunWith(JUnit4.class)
public class AppInfoTest {
+ private static final long DEFAULT_VERSION = 2L;
private static final String APP_INFO_HR_PATH = "com/android/asllib/appinfo/hr";
private static final String APP_INFO_OD_PATH = "com/android/asllib/appinfo/od";
public static final List<String> REQUIRED_FIELD_NAMES =
@@ -45,7 +47,24 @@ public class AppInfoTest {
public static final List<String> OPTIONAL_FIELD_NAMES = List.of();
public static final List<String> OPTIONAL_FIELD_NAMES_OD = List.of();
+ public static final List<String> REQUIRED_FIELD_NAMES_OD_V1 =
+ List.of(
+ "title",
+ "description",
+ "contains_ads",
+ "obey_aps",
+ "ads_fingerprinting",
+ "security_fingerprinting",
+ "privacy_policy",
+ "security_endpoints",
+ "first_party_endpoints",
+ "service_provider_endpoints",
+ "category");
+ public static final List<String> OPTIONAL_FIELD_NAMES_OD_V1 = List.of("website", "email");
+
private static final String ALL_FIELDS_VALID_FILE_NAME = "all-fields-valid.xml";
+ private static final String ALL_FIELDS_VALID_V1_FILE_NAME = "all-fields-valid-v1.xml";
+ public static final String UNRECOGNIZED_V1_FILE_NAME = "unrecognized-v1.xml";
/** Logic for setting up tests (empty if not yet needed). */
public static void main(String[] params) throws Exception {}
@@ -63,6 +82,61 @@ public class AppInfoTest {
testOdToHrAppInfo(ALL_FIELDS_VALID_FILE_NAME);
}
+ /** Test for all fields valid v1. */
+ @Test
+ public void testAllFieldsValidV1() throws Exception {
+ System.out.println("starting testAllFieldsValidV1.");
+ new AppInfoFactory()
+ .createFromOdElement(
+ TestUtils.getElementFromResource(
+ Paths.get(APP_INFO_OD_PATH, ALL_FIELDS_VALID_V1_FILE_NAME)),
+ 1L);
+ }
+
+ /** Test for unrecognized field v1. */
+ @Test
+ public void testUnrecognizedFieldV1() throws Exception {
+ System.out.println("starting testUnrecognizedFieldV1.");
+ assertThrows(
+ MalformedXmlException.class,
+ () ->
+ new AppInfoFactory()
+ .createFromOdElement(
+ TestUtils.getElementFromResource(
+ Paths.get(
+ APP_INFO_OD_PATH,
+ UNRECOGNIZED_V1_FILE_NAME)),
+ 1L));
+ }
+
+ /** Tests missing required fields fails, V1. */
+ @Test
+ public void testMissingRequiredFieldsOdV1() throws Exception {
+ for (String reqField : REQUIRED_FIELD_NAMES_OD_V1) {
+ System.out.println("testing missing required field od v1: " + reqField);
+ var appInfoEle =
+ TestUtils.getElementFromResource(
+ Paths.get(APP_INFO_OD_PATH, ALL_FIELDS_VALID_V1_FILE_NAME));
+ TestUtils.removeOdChildEleWithName(appInfoEle, reqField);
+ assertThrows(
+ MalformedXmlException.class,
+ () -> new AppInfoFactory().createFromOdElement(appInfoEle, 1L));
+ }
+ }
+
+ /** Tests missing optional fields passes, V1. */
+ @Test
+ public void testMissingOptionalFieldsOdV1() throws Exception {
+ for (String optField : OPTIONAL_FIELD_NAMES_OD_V1) {
+ System.out.println("testing missing optional field od v1: " + optField);
+ var appInfoEle =
+ TestUtils.getElementFromResource(
+ Paths.get(APP_INFO_OD_PATH, ALL_FIELDS_VALID_V1_FILE_NAME));
+ TestUtils.removeOdChildEleWithName(appInfoEle, optField);
+ new AppInfoFactory().createFromOdElement(appInfoEle, 1L);
+ }
+ }
+
/** Tests missing required fields fails. */
@Test
public void testMissingRequiredFields() throws Exception {
@@ -70,24 +144,24 @@ public class AppInfoTest {
for (String reqField : REQUIRED_FIELD_NAMES) {
System.out.println("testing missing required field hr: " + reqField);
var appInfoEle =
- TestUtils.getElementsFromResource(
+ TestUtils.getElementFromResource(
Paths.get(APP_INFO_HR_PATH, ALL_FIELDS_VALID_FILE_NAME));
- appInfoEle.get(0).removeAttribute(reqField);
+ appInfoEle.removeAttribute(reqField);
assertThrows(
MalformedXmlException.class,
- () -> new AppInfoFactory().createFromHrElements(appInfoEle));
+ () -> new AppInfoFactory().createFromHrElement(appInfoEle, DEFAULT_VERSION));
}
for (String reqField : REQUIRED_FIELD_NAMES_OD) {
System.out.println("testing missing required field od: " + reqField);
var appInfoEle =
- TestUtils.getElementsFromResource(
+ TestUtils.getElementFromResource(
Paths.get(APP_INFO_OD_PATH, ALL_FIELDS_VALID_FILE_NAME));
- TestUtils.removeOdChildEleWithName(appInfoEle.get(0), reqField);
+ TestUtils.removeOdChildEleWithName(appInfoEle, reqField);
assertThrows(
MalformedXmlException.class,
- () -> new AppInfoFactory().createFromOdElements(appInfoEle));
+ () -> new AppInfoFactory().createFromOdElement(appInfoEle, DEFAULT_VERSION));
}
}
@@ -98,24 +172,24 @@ public class AppInfoTest {
for (String reqChildName : REQUIRED_CHILD_NAMES) {
System.out.println("testing missing required child hr: " + reqChildName);
var appInfoEle =
- TestUtils.getElementsFromResource(
+ TestUtils.getElementFromResource(
Paths.get(APP_INFO_HR_PATH, ALL_FIELDS_VALID_FILE_NAME));
- var child = XmlUtils.getChildrenByTagName(appInfoEle.get(0), reqChildName).get(0);
- appInfoEle.get(0).removeChild(child);
+ var child = XmlUtils.getChildrenByTagName(appInfoEle, reqChildName).get(0);
+ appInfoEle.removeChild(child);
assertThrows(
MalformedXmlException.class,
- () -> new AppInfoFactory().createFromHrElements(appInfoEle));
+ () -> new AppInfoFactory().createFromHrElement(appInfoEle, DEFAULT_VERSION));
}
for (String reqField : REQUIRED_CHILD_NAMES_OD) {
System.out.println("testing missing required child od: " + reqField);
var appInfoEle =
- TestUtils.getElementsFromResource(
+ TestUtils.getElementFromResource(
Paths.get(APP_INFO_OD_PATH, ALL_FIELDS_VALID_FILE_NAME));
- TestUtils.removeOdChildEleWithName(appInfoEle.get(0), reqField);
+ TestUtils.removeOdChildEleWithName(appInfoEle, reqField);
assertThrows(
MalformedXmlException.class,
- () -> new AppInfoFactory().createFromOdElements(appInfoEle));
+ () -> new AppInfoFactory().createFromOdElement(appInfoEle, DEFAULT_VERSION));
}
}
@@ -124,38 +198,51 @@ public class AppInfoTest {
public void testMissingOptionalFields() throws Exception {
for (String optField : OPTIONAL_FIELD_NAMES) {
var ele =
- TestUtils.getElementsFromResource(
+ TestUtils.getElementFromResource(
Paths.get(APP_INFO_HR_PATH, ALL_FIELDS_VALID_FILE_NAME));
- ele.get(0).removeAttribute(optField);
- AppInfo appInfo = new AppInfoFactory().createFromHrElements(ele);
- appInfo.toOdDomElements(TestUtils.document());
+ ele.removeAttribute(optField);
+ AppInfo appInfo = new AppInfoFactory().createFromHrElement(ele, DEFAULT_VERSION);
+ appInfo.toOdDomElement(TestUtils.document());
}
for (String optField : OPTIONAL_FIELD_NAMES_OD) {
var ele =
- TestUtils.getElementsFromResource(
+ TestUtils.getElementFromResource(
Paths.get(APP_INFO_OD_PATH, ALL_FIELDS_VALID_FILE_NAME));
- TestUtils.removeOdChildEleWithName(ele.get(0), optField);
- AppInfo appInfo = new AppInfoFactory().createFromOdElements(ele);
- appInfo.toHrDomElements(TestUtils.document());
+ TestUtils.removeOdChildEleWithName(ele, optField);
+ AppInfo appInfo = new AppInfoFactory().createFromOdElement(ele, DEFAULT_VERSION);
+ appInfo.toHrDomElement(TestUtils.document());
}
}
private void testHrToOdAppInfo(String fileName) throws Exception {
- TestUtils.testHrToOd(
- TestUtils.document(),
- new AppInfoFactory(),
- APP_INFO_HR_PATH,
- APP_INFO_OD_PATH,
- fileName);
+ var doc = TestUtils.document();
+ AppInfo appInfo =
+ new AppInfoFactory()
+ .createFromHrElement(
+ TestUtils.getElementFromResource(
+ Paths.get(APP_INFO_HR_PATH, fileName)),
+ DEFAULT_VERSION);
+ Element appInfoEle = appInfo.toOdDomElement(doc);
+ doc.appendChild(appInfoEle);
+ TestUtils.testFormatToFormat(doc, Paths.get(APP_INFO_OD_PATH, fileName));
}
+
private void testOdToHrAppInfo(String fileName) throws Exception {
- TestUtils.testOdToHr(
- TestUtils.document(),
- new AppInfoFactory(),
- APP_INFO_OD_PATH,
- APP_INFO_HR_PATH,
- fileName);
+ testOdToHrAppInfo(fileName, DEFAULT_VERSION);
+ }
+
+ private void testOdToHrAppInfo(String fileName, long version) throws Exception {
+ var doc = TestUtils.document();
+ AppInfo appInfo =
+ new AppInfoFactory()
+ .createFromOdElement(
+ TestUtils.getElementFromResource(
+ Paths.get(APP_INFO_OD_PATH, fileName)),
+ version);
+ Element appInfoEle = appInfo.toHrDomElement(doc);
+ doc.appendChild(appInfoEle);
+ TestUtils.testFormatToFormat(doc, Paths.get(APP_INFO_HR_PATH, fileName));
}
}
diff --git a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/DataLabelsTest.java b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/DataLabelsTest.java
index ff4374166dd3..b557fea9572b 100644
--- a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/DataLabelsTest.java
+++ b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/DataLabelsTest.java
@@ -16,15 +16,27 @@
package com.android.asllib.marshallable;
+import static org.junit.Assert.assertThrows;
+
import com.android.asllib.testutils.TestUtils;
+import com.android.asllib.util.MalformedXmlException;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+import org.w3c.dom.Element;
+import org.xml.sax.SAXException;
+
+import java.io.IOException;
+import java.nio.file.Paths;
+
+import javax.xml.parsers.ParserConfigurationException;
@RunWith(JUnit4.class)
public class DataLabelsTest {
+ private static final long DEFAULT_VERSION = 2L;
+
private static final String DATA_LABELS_HR_PATH = "com/android/asllib/datalabels/hr";
private static final String DATA_LABELS_OD_PATH = "com/android/asllib/datalabels/od";
@@ -297,29 +309,43 @@ public class DataLabelsTest {
odToHrExpectException(PERSONAL_EMPTY_PURPOSE_FILE_NAME);
}
- private void hrToOdExpectException(String fileName) {
- TestUtils.hrToOdExpectException(new DataLabelsFactory(), DATA_LABELS_HR_PATH, fileName);
+ private void hrToOdExpectException(String fileName)
+ throws ParserConfigurationException, IOException, SAXException {
+ var ele = TestUtils.getElementFromResource(Paths.get(DATA_LABELS_HR_PATH, fileName));
+ assertThrows(
+ MalformedXmlException.class,
+ () -> new DataLabelsFactory().createFromHrElement(ele));
}
- private void odToHrExpectException(String fileName) {
- TestUtils.odToHrExpectException(new DataLabelsFactory(), DATA_LABELS_OD_PATH, fileName);
+ private void odToHrExpectException(String fileName)
+ throws ParserConfigurationException, IOException, SAXException {
+ var ele = TestUtils.getElementFromResource(Paths.get(DATA_LABELS_OD_PATH, fileName));
+ assertThrows(
+ MalformedXmlException.class,
+ () -> new DataLabelsFactory().createFromOdElement(ele));
}
private void testHrToOdDataLabels(String fileName) throws Exception {
- TestUtils.testHrToOd(
- TestUtils.document(),
- new DataLabelsFactory(),
- DATA_LABELS_HR_PATH,
- DATA_LABELS_OD_PATH,
- fileName);
+ var doc = TestUtils.document();
+ DataLabels dataLabels =
+ new DataLabelsFactory()
+ .createFromHrElement(
+ TestUtils.getElementFromResource(
+ Paths.get(DATA_LABELS_HR_PATH, fileName)));
+ Element resultingEle = dataLabels.toOdDomElement(doc);
+ doc.appendChild(resultingEle);
+ TestUtils.testFormatToFormat(doc, Paths.get(DATA_LABELS_OD_PATH, fileName));
}
private void testOdToHrDataLabels(String fileName) throws Exception {
- TestUtils.testOdToHr(
- TestUtils.document(),
- new DataLabelsFactory(),
- DATA_LABELS_OD_PATH,
- DATA_LABELS_HR_PATH,
- fileName);
+ var doc = TestUtils.document();
+ DataLabels dataLabels =
+ new DataLabelsFactory()
+ .createFromOdElement(
+ TestUtils.getElementFromResource(
+ Paths.get(DATA_LABELS_OD_PATH, fileName)));
+ Element resultingEle = dataLabels.toHrDomElement(doc);
+ doc.appendChild(resultingEle);
+ TestUtils.testFormatToFormat(doc, Paths.get(DATA_LABELS_HR_PATH, fileName));
}
}
diff --git a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/SafetyLabelsTest.java b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/SafetyLabelsTest.java
index 19d1626f7054..7cd510f0ddfc 100644
--- a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/SafetyLabelsTest.java
+++ b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/SafetyLabelsTest.java
@@ -16,15 +16,27 @@
package com.android.asllib.marshallable;
+import static org.junit.Assert.assertThrows;
+
import com.android.asllib.testutils.TestUtils;
+import com.android.asllib.util.MalformedXmlException;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+import org.w3c.dom.Element;
+import org.xml.sax.SAXException;
+
+import java.io.IOException;
+import java.nio.file.Paths;
+
+import javax.xml.parsers.ParserConfigurationException;
@RunWith(JUnit4.class)
public class SafetyLabelsTest {
+ private static final long DEFAULT_VERSION = 2L;
+
private static final String SAFETY_LABELS_HR_PATH = "com/android/asllib/safetylabels/hr";
private static final String SAFETY_LABELS_OD_PATH = "com/android/asllib/safetylabels/od";
@@ -52,29 +64,51 @@ public class SafetyLabelsTest {
testOdToHrSafetyLabels(WITH_DATA_LABELS_FILE_NAME);
}
- private void hrToOdExpectException(String fileName) {
- TestUtils.hrToOdExpectException(new SafetyLabelsFactory(), SAFETY_LABELS_HR_PATH, fileName);
+ private void hrToOdExpectException(String fileName)
+ throws ParserConfigurationException, IOException, SAXException {
+ var safetyLabelsEle =
+ TestUtils.getElementFromResource(Paths.get(SAFETY_LABELS_HR_PATH, fileName));
+ assertThrows(
+ MalformedXmlException.class,
+ () ->
+ new SafetyLabelsFactory()
+ .createFromHrElement(safetyLabelsEle, DEFAULT_VERSION));
}
- private void odToHrExpectException(String fileName) {
- TestUtils.odToHrExpectException(new SafetyLabelsFactory(), SAFETY_LABELS_OD_PATH, fileName);
+ private void odToHrExpectException(String fileName)
+ throws ParserConfigurationException, IOException, SAXException {
+ var safetyLabelsEle =
+ TestUtils.getElementFromResource(Paths.get(SAFETY_LABELS_OD_PATH, fileName));
+ assertThrows(
+ MalformedXmlException.class,
+ () ->
+ new SafetyLabelsFactory()
+ .createFromOdElement(safetyLabelsEle, DEFAULT_VERSION));
}
private void testHrToOdSafetyLabels(String fileName) throws Exception {
- TestUtils.testHrToOd(
- TestUtils.document(),
- new SafetyLabelsFactory(),
- SAFETY_LABELS_HR_PATH,
- SAFETY_LABELS_OD_PATH,
- fileName);
+ var doc = TestUtils.document();
+ SafetyLabels safetyLabels =
+ new SafetyLabelsFactory()
+ .createFromHrElement(
+ TestUtils.getElementFromResource(
+ Paths.get(SAFETY_LABELS_HR_PATH, fileName)),
+ DEFAULT_VERSION);
+ Element appInfoEle = safetyLabels.toOdDomElement(doc);
+ doc.appendChild(appInfoEle);
+ TestUtils.testFormatToFormat(doc, Paths.get(SAFETY_LABELS_OD_PATH, fileName));
}
private void testOdToHrSafetyLabels(String fileName) throws Exception {
- TestUtils.testOdToHr(
- TestUtils.document(),
- new SafetyLabelsFactory(),
- SAFETY_LABELS_OD_PATH,
- SAFETY_LABELS_HR_PATH,
- fileName);
+ var doc = TestUtils.document();
+ SafetyLabels safetyLabels =
+ new SafetyLabelsFactory()
+ .createFromOdElement(
+ TestUtils.getElementFromResource(
+ Paths.get(SAFETY_LABELS_OD_PATH, fileName)),
+ DEFAULT_VERSION);
+ Element appInfoEle = safetyLabels.toHrDomElement(doc);
+ doc.appendChild(appInfoEle);
+ TestUtils.testFormatToFormat(doc, Paths.get(SAFETY_LABELS_HR_PATH, fileName));
}
}
diff --git a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/SystemAppSafetyLabelTest.java b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/SystemAppSafetyLabelTest.java
index 87d3e4499f5c..9dcc6529969e 100644
--- a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/SystemAppSafetyLabelTest.java
+++ b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/SystemAppSafetyLabelTest.java
@@ -16,15 +16,27 @@
package com.android.asllib.marshallable;
+import static org.junit.Assert.assertThrows;
+
import com.android.asllib.testutils.TestUtils;
+import com.android.asllib.util.MalformedXmlException;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+import org.w3c.dom.Element;
+import org.xml.sax.SAXException;
+
+import java.io.IOException;
+import java.nio.file.Paths;
+
+import javax.xml.parsers.ParserConfigurationException;
@RunWith(JUnit4.class)
public class SystemAppSafetyLabelTest {
+ private static final long DEFAULT_VERSION = 2L;
+
private static final String SYSTEM_APP_SAFETY_LABEL_HR_PATH =
"com/android/asllib/systemappsafetylabel/hr";
private static final String SYSTEM_APP_SAFETY_LABEL_OD_PATH =
@@ -57,31 +69,49 @@ public class SystemAppSafetyLabelTest {
odToHrExpectException(MISSING_BOOL_FILE_NAME);
}
- private void hrToOdExpectException(String fileName) {
- TestUtils.hrToOdExpectException(
- new SystemAppSafetyLabelFactory(), SYSTEM_APP_SAFETY_LABEL_HR_PATH, fileName);
+ private void hrToOdExpectException(String fileName)
+ throws ParserConfigurationException, IOException, SAXException {
+ var ele =
+ TestUtils.getElementFromResource(
+ Paths.get(SYSTEM_APP_SAFETY_LABEL_HR_PATH, fileName));
+ assertThrows(
+ MalformedXmlException.class,
+ () -> new SystemAppSafetyLabelFactory().createFromHrElement(ele, DEFAULT_VERSION));
}
- private void odToHrExpectException(String fileName) {
- TestUtils.odToHrExpectException(
- new SystemAppSafetyLabelFactory(), SYSTEM_APP_SAFETY_LABEL_OD_PATH, fileName);
+ private void odToHrExpectException(String fileName)
+ throws ParserConfigurationException, IOException, SAXException {
+ var ele =
+ TestUtils.getElementFromResource(
+ Paths.get(SYSTEM_APP_SAFETY_LABEL_OD_PATH, fileName));
+ assertThrows(
+ MalformedXmlException.class,
+ () -> new SystemAppSafetyLabelFactory().createFromOdElement(ele, DEFAULT_VERSION));
}
private void testHrToOdSystemAppSafetyLabel(String fileName) throws Exception {
- TestUtils.testHrToOd(
- TestUtils.document(),
- new SystemAppSafetyLabelFactory(),
- SYSTEM_APP_SAFETY_LABEL_HR_PATH,
- SYSTEM_APP_SAFETY_LABEL_OD_PATH,
- fileName);
+ var doc = TestUtils.document();
+ SystemAppSafetyLabel systemAppSafetyLabel =
+ new SystemAppSafetyLabelFactory()
+ .createFromHrElement(
+ TestUtils.getElementFromResource(
+ Paths.get(SYSTEM_APP_SAFETY_LABEL_HR_PATH, fileName)),
+ DEFAULT_VERSION);
+ Element resultingEle = systemAppSafetyLabel.toOdDomElement(doc);
+ doc.appendChild(resultingEle);
+ TestUtils.testFormatToFormat(doc, Paths.get(SYSTEM_APP_SAFETY_LABEL_OD_PATH, fileName));
}
private void testOdToHrSystemAppSafetyLabel(String fileName) throws Exception {
- TestUtils.testOdToHr(
- TestUtils.document(),
- new SystemAppSafetyLabelFactory(),
- SYSTEM_APP_SAFETY_LABEL_OD_PATH,
- SYSTEM_APP_SAFETY_LABEL_HR_PATH,
- fileName);
+ var doc = TestUtils.document();
+ SystemAppSafetyLabel systemAppSafetyLabel =
+ new SystemAppSafetyLabelFactory()
+ .createFromOdElement(
+ TestUtils.getElementFromResource(
+ Paths.get(SYSTEM_APP_SAFETY_LABEL_OD_PATH, fileName)),
+ DEFAULT_VERSION);
+ Element resultingEle = systemAppSafetyLabel.toHrDomElement(doc);
+ doc.appendChild(resultingEle);
+ TestUtils.testFormatToFormat(doc, Paths.get(SYSTEM_APP_SAFETY_LABEL_HR_PATH, fileName));
}
}
diff --git a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/TransparencyInfoTest.java b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/TransparencyInfoTest.java
index 8a0b35eac7c8..6547fb952944 100644
--- a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/TransparencyInfoTest.java
+++ b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/TransparencyInfoTest.java
@@ -22,9 +22,14 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+import org.w3c.dom.Element;
+
+import java.nio.file.Paths;
@RunWith(JUnit4.class)
public class TransparencyInfoTest {
+ private static final long DEFAULT_VERSION = 2L;
+
private static final String TRANSPARENCY_INFO_HR_PATH =
"com/android/asllib/transparencyinfo/hr";
private static final String TRANSPARENCY_INFO_OD_PATH =
@@ -45,20 +50,28 @@ public class TransparencyInfoTest {
}
private void testHrToOdTransparencyInfo(String fileName) throws Exception {
- TestUtils.testHrToOd(
- TestUtils.document(),
- new TransparencyInfoFactory(),
- TRANSPARENCY_INFO_HR_PATH,
- TRANSPARENCY_INFO_OD_PATH,
- fileName);
+ var doc = TestUtils.document();
+ TransparencyInfo transparencyInfo =
+ new TransparencyInfoFactory()
+ .createFromHrElement(
+ TestUtils.getElementFromResource(
+ Paths.get(TRANSPARENCY_INFO_HR_PATH, fileName)),
+ DEFAULT_VERSION);
+ Element resultingEle = transparencyInfo.toOdDomElement(doc);
+ doc.appendChild(resultingEle);
+ TestUtils.testFormatToFormat(doc, Paths.get(TRANSPARENCY_INFO_OD_PATH, fileName));
}
private void testOdToHrTransparencyInfo(String fileName) throws Exception {
- TestUtils.testOdToHr(
- TestUtils.document(),
- new TransparencyInfoFactory(),
- TRANSPARENCY_INFO_OD_PATH,
- TRANSPARENCY_INFO_HR_PATH,
- fileName);
+ var doc = TestUtils.document();
+ TransparencyInfo transparencyInfo =
+ new TransparencyInfoFactory()
+ .createFromOdElement(
+ TestUtils.getElementFromResource(
+ Paths.get(TRANSPARENCY_INFO_OD_PATH, fileName)),
+ DEFAULT_VERSION);
+ Element resultingEle = transparencyInfo.toHrDomElement(doc);
+ doc.appendChild(resultingEle);
+ TestUtils.testFormatToFormat(doc, Paths.get(TRANSPARENCY_INFO_HR_PATH, fileName));
}
}
diff --git a/tools/app_metadata_bundles/src/test/java/com/android/asllib/testutils/TestUtils.java b/tools/app_metadata_bundles/src/test/java/com/android/asllib/testutils/TestUtils.java
index ea90993e0785..f8ef40a9c509 100644
--- a/tools/app_metadata_bundles/src/test/java/com/android/asllib/testutils/TestUtils.java
+++ b/tools/app_metadata_bundles/src/test/java/com/android/asllib/testutils/TestUtils.java
@@ -17,11 +17,8 @@
package com.android.asllib.testutils;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThrows;
import com.android.asllib.marshallable.AslMarshallable;
-import com.android.asllib.marshallable.AslMarshallableFactory;
-import com.android.asllib.util.MalformedXmlException;
import com.android.asllib.util.XmlUtils;
import org.w3c.dom.Document;
@@ -36,7 +33,6 @@ import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
-import java.nio.file.Paths;
import java.util.List;
import java.util.Optional;
@@ -60,7 +56,19 @@ public class TestUtils {
}
/** Gets List of Element from a path to an existing Resource. */
- public static List<Element> getElementsFromResource(Path filePath)
+ public static Element getElementFromResource(Path filePath)
+ throws ParserConfigurationException, IOException, SAXException {
+ String str = readStrFromResource(filePath);
+ InputStream stream = new ByteArrayInputStream(str.getBytes(StandardCharsets.UTF_8));
+
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ factory.setNamespaceAware(true);
+ Document document = factory.newDocumentBuilder().parse(stream);
+ return document.getDocumentElement();
+ }
+
+ /** Gets List of Element from a path to an existing Resource. */
+ public static List<Element> getChildElementsFromResource(Path filePath)
throws ParserConfigurationException, IOException, SAXException {
String str = readStrFromResource(filePath);
InputStream stream = new ByteArrayInputStream(str.getBytes(StandardCharsets.UTF_8));
@@ -69,16 +77,13 @@ public class TestUtils {
factory.setNamespaceAware(true);
Document document = factory.newDocumentBuilder().parse(stream);
Element root = document.getDocumentElement();
- if (root.getTagName().equals(HOLDER_TAG_NAME)) {
- String tagName =
- XmlUtils.asElementList(root.getChildNodes()).stream()
- .findFirst()
- .get()
- .getTagName();
- return XmlUtils.getChildrenByTagName(root, tagName);
- } else {
- return List.of(root);
- }
+
+ String tagName =
+ XmlUtils.asElementList(root.getChildNodes()).stream()
+ .findFirst()
+ .get()
+ .getTagName();
+ return XmlUtils.getChildrenByTagName(root, tagName);
}
/** Reads a Document into a String. */
@@ -130,86 +135,13 @@ public class TestUtils {
return DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
}
- /** Helper for testing human-readable to on-device conversion expecting exception */
- public static <T extends AslMarshallable> void hrToOdExpectException(
- AslMarshallableFactory<T> factory, String hrFolderPath, String fileName) {
- assertThrows(
- MalformedXmlException.class,
- () -> {
- factory.createFromHrElements(
- TestUtils.getElementsFromResource(Paths.get(hrFolderPath, fileName)));
- });
- }
-
- /** Helper for testing on-device to human-readable conversion expecting exception */
- public static <T extends AslMarshallable> void odToHrExpectException(
- AslMarshallableFactory<T> factory, String odFolderPath, String fileName) {
- assertThrows(
- MalformedXmlException.class,
- () -> {
- factory.createFromOdElements(
- TestUtils.getElementsFromResource(Paths.get(odFolderPath, fileName)));
- });
- }
-
- /** Helper for testing human-readable to on-device conversion */
- public static <T extends AslMarshallable> void testHrToOd(
- Document doc,
- AslMarshallableFactory<T> factory,
- String hrFolderPath,
- String odFolderPath,
- String fileName)
- throws Exception {
- testFormatToFormat(doc, factory, hrFolderPath, odFolderPath, fileName, true);
- }
-
- /** Helper for testing on-device to human-readable conversion */
- public static <T extends AslMarshallable> void testOdToHr(
- Document doc,
- AslMarshallableFactory<T> factory,
- String odFolderPath,
- String hrFolderPath,
- String fileName)
- throws Exception {
- testFormatToFormat(doc, factory, odFolderPath, hrFolderPath, fileName, false);
- }
-
/** Helper for testing format to format conversion */
- private static <T extends AslMarshallable> void testFormatToFormat(
- Document doc,
- AslMarshallableFactory<T> factory,
- String inFolderPath,
- String outFolderPath,
- String fileName,
- boolean hrToOd)
- throws Exception {
- AslMarshallable marshallable =
- hrToOd
- ? factory.createFromHrElements(
- TestUtils.getElementsFromResource(
- Paths.get(inFolderPath, fileName)))
- : factory.createFromOdElements(
- TestUtils.getElementsFromResource(
- Paths.get(inFolderPath, fileName)));
-
- List<Element> elements =
- hrToOd ? marshallable.toOdDomElements(doc) : marshallable.toHrDomElements(doc);
- if (elements.isEmpty()) {
- throw new IllegalStateException("elements was empty.");
- } else if (elements.size() == 1) {
- doc.appendChild(elements.get(0));
- } else {
- Element root = doc.createElement(TestUtils.HOLDER_TAG_NAME);
- for (var child : elements) {
- root.appendChild(child);
- }
- doc.appendChild(root);
- }
+ public static <T extends AslMarshallable> void testFormatToFormat(
+ Document doc, Path expectedOutPath) throws Exception {
String converted = TestUtils.getFormattedXml(TestUtils.docToStr(doc, true), true);
System.out.println("Converted: " + converted);
String expectedOutContents =
- TestUtils.getFormattedXml(
- TestUtils.readStrFromResource(Paths.get(outFolderPath, fileName)), true);
+ TestUtils.getFormattedXml(TestUtils.readStrFromResource(expectedOutPath), true);
System.out.println("Expected: " + expectedOutContents);
assertEquals(expectedOutContents, converted);
}
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/missing-version.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/missing-version.xml
index ec0cd702fd43..7478e39ce366 100644
--- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/missing-version.xml
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/missing-version.xml
@@ -1,3 +1,17 @@
<app-metadata-bundles>
-
+ <system-app-safety-label declaration="true">
+ </system-app-safety-label>
+ <transparency-info>
+ <app-info
+ apsCompliant="false"
+ privacyPolicy="www.example.com" developerId="dev1" applicationId="app1">
+ <first-party-endpoints>
+ <item>url1</item>
+ </first-party-endpoints>
+ <service-provider-endpoints>
+ <item>url55</item>
+ <item>url56</item>
+ </service-provider-endpoints>
+ </app-info>
+ </transparency-info>
</app-metadata-bundles> \ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/valid-empty.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/valid-empty.xml
index 19bfd826f770..587c49add47e 100644
--- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/valid-empty.xml
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/valid-empty.xml
@@ -1 +1,17 @@
-<app-metadata-bundles version="123456"></app-metadata-bundles> \ No newline at end of file
+<app-metadata-bundles version="2">
+ <system-app-safety-label declaration="true">
+ </system-app-safety-label>
+ <transparency-info>
+ <app-info
+ apsCompliant="false"
+ privacyPolicy="www.example.com" developerId="dev1" applicationId="app1">
+ <first-party-endpoints>
+ <item>url1</item>
+ </first-party-endpoints>
+ <service-provider-endpoints>
+ <item>url55</item>
+ <item>url56</item>
+ </service-provider-endpoints>
+ </app-info>
+ </transparency-info>
+</app-metadata-bundles> \ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/with-safety-labels.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/with-safety-labels.xml
index 03e71d28f4cc..9cfb8bc4d5da 100644
--- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/with-safety-labels.xml
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/with-safety-labels.xml
@@ -1,4 +1,19 @@
-<app-metadata-bundles version="123456">
+<app-metadata-bundles version="2">
<safety-labels>
</safety-labels>
+ <system-app-safety-label declaration="true">
+ </system-app-safety-label>
+ <transparency-info>
+ <app-info
+ apsCompliant="false"
+ privacyPolicy="www.example.com" developerId="dev1" applicationId="app1">
+ <first-party-endpoints>
+ <item>url1</item>
+ </first-party-endpoints>
+ <service-provider-endpoints>
+ <item>url55</item>
+ <item>url56</item>
+ </service-provider-endpoints>
+ </app-info>
+ </transparency-info>
</app-metadata-bundles> \ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/with-system-app-safety-label.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/with-system-app-safety-label.xml
deleted file mode 100644
index afb048632bc6..000000000000
--- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/with-system-app-safety-label.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<app-metadata-bundles version="123456">
-<system-app-safety-label declaration="true">
-</system-app-safety-label>
-</app-metadata-bundles> \ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/with-transparency-info.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/with-transparency-info.xml
deleted file mode 100644
index a00ef6565cf4..000000000000
--- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/with-transparency-info.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<app-metadata-bundles version="123456">
- <transparency-info>
- <app-info
- apsCompliant="false"
- privacyPolicy="www.example.com">
- <first-party-endpoints>
- <item>url1</item>
- </first-party-endpoints>
- <service-provider-endpoints>
- <item>url55</item>
- <item>url56</item>
- </service-provider-endpoints>
- </app-info>
- </transparency-info>
-</app-metadata-bundles> \ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/missing-version.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/missing-version.xml
index 1aa3aa94ca6d..9adfa98f05a3 100644
--- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/missing-version.xml
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/missing-version.xml
@@ -1,2 +1,20 @@
<bundle>
+ <pbundle_as_map name="system_app_safety_label">
+ <boolean name="declaration" value="true"/>
+ </pbundle_as_map>
+ <pbundle_as_map name="transparency_info">
+ <pbundle_as_map name="app_info">
+ <boolean name="aps_compliant" value="false"/>
+ <string name="privacy_policy" value="www.example.com"/>
+ <string-array name="first_party_endpoints" num="1">
+ <item value="url1"/>
+ </string-array>
+ <string-array name="service_provider_endpoints" num="2">
+ <item value="url55"/>
+ <item value="url56"/>
+ </string-array>
+ <string name="developer_id" value="dev1"/>
+ <string name="application_id" value="app1"/>
+ </pbundle_as_map>
+ </pbundle_as_map>
</bundle> \ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/valid-empty.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/valid-empty.xml
index 37bdfad4065f..7a4c82a9e65f 100644
--- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/valid-empty.xml
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/valid-empty.xml
@@ -1,3 +1,21 @@
<bundle>
- <long name="version" value="123456"/>
+ <long name="version" value="2"/>
+ <pbundle_as_map name="system_app_safety_label">
+ <boolean name="declaration" value="true"/>
+ </pbundle_as_map>
+ <pbundle_as_map name="transparency_info">
+ <pbundle_as_map name="app_info">
+ <string name="privacy_policy" value="www.example.com"/>
+ <string-array name="first_party_endpoints" num="1">
+ <item value="url1"/>
+ </string-array>
+ <string-array name="service_provider_endpoints" num="2">
+ <item value="url55"/>
+ <item value="url56"/>
+ </string-array>
+ <boolean name="aps_compliant" value="false"/>
+ <string name="developer_id" value="dev1"/>
+ <string name="application_id" value="app1"/>
+ </pbundle_as_map>
+ </pbundle_as_map>
</bundle> \ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/with-safety-labels.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/with-safety-labels.xml
index f00fb26bf1ee..3a3e5d383ca9 100644
--- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/with-safety-labels.xml
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/with-safety-labels.xml
@@ -1,5 +1,22 @@
<bundle>
- <long name="version" value="123456"/>
- <pbundle_as_map name="safety_labels">
+ <long name="version" value="2"/>
+ <pbundle_as_map name="safety_labels"/>
+ <pbundle_as_map name="system_app_safety_label">
+ <boolean name="declaration" value="true"/>
</pbundle_as_map>
-</bundle>
+ <pbundle_as_map name="transparency_info">
+ <pbundle_as_map name="app_info">
+ <string name="privacy_policy" value="www.example.com"/>
+ <string-array name="first_party_endpoints" num="1">
+ <item value="url1"/>
+ </string-array>
+ <string-array name="service_provider_endpoints" num="2">
+ <item value="url55"/>
+ <item value="url56"/>
+ </string-array>
+ <boolean name="aps_compliant" value="false"/>
+ <string name="developer_id" value="dev1"/>
+ <string name="application_id" value="app1"/>
+ </pbundle_as_map>
+ </pbundle_as_map>
+</bundle> \ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/with-system-app-safety-label.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/with-system-app-safety-label.xml
deleted file mode 100644
index e8640c4f0934..000000000000
--- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/with-system-app-safety-label.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<bundle>
- <long name="version" value="123456"/>
- <pbundle_as_map name="system_app_safety_label">
- <boolean name="declaration" value="true"/>
- </pbundle_as_map>
-</bundle> \ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/with-transparency-info.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/with-transparency-info.xml
deleted file mode 100644
index d0c8668564bd..000000000000
--- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/with-transparency-info.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<bundle>
- <long name="version" value="123456"/>
- <pbundle_as_map name="transparency_info">
- <pbundle_as_map name="app_info">
- <boolean name="aps_compliant" value="false"/>
- <string name="privacy_policy" value="www.example.com"/>
- <string-array name="first_party_endpoints" num="1">
- <item value="url1"/>
- </string-array>
- <string-array name="service_provider_endpoints" num="2">
- <item value="url55"/>
- <item value="url56"/>
- </string-array>
- </pbundle_as_map>
- </pbundle_as_map>
-</bundle> \ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/appinfo/hr/all-fields-valid.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/appinfo/hr/all-fields-valid.xml
index 0d15efc4eac3..306e01533731 100644
--- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/appinfo/hr/all-fields-valid.xml
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/appinfo/hr/all-fields-valid.xml
@@ -1,6 +1,6 @@
<app-info
apsCompliant="false"
- privacyPolicy="www.example.com">
+ privacyPolicy="www.example.com" developerId="dev1" applicationId="app1">
<first-party-endpoints>
<item>url1</item>
</first-party-endpoints>
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/appinfo/od/all-fields-valid-v1.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/appinfo/od/all-fields-valid-v1.xml
new file mode 100644
index 000000000000..b026cf33e5f0
--- /dev/null
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/appinfo/od/all-fields-valid-v1.xml
@@ -0,0 +1,24 @@
+<pbundle_as_map name="app_info">
+ <string name="title" value="beervision"/>
+ <string name="description" value="a beer app"/>
+ <boolean name="contains_ads" value="true"/>
+ <boolean name="obey_aps" value="false"/>
+ <boolean name="ads_fingerprinting" value="false"/>
+ <boolean name="security_fingerprinting" value="false"/>
+ <string name="privacy_policy" value="www.example.com"/>
+ <string-array name="security_endpoints" num="3">
+ <item value="url1"/>
+ <item value="url2"/>
+ <item value="url3"/>
+ </string-array>
+ <string-array name="first_party_endpoints" num="1">
+ <item value="url1"/>
+ </string-array>
+ <string-array name="service_provider_endpoints" num="2">
+ <item value="url55"/>
+ <item value="url56"/>
+ </string-array>
+ <string name="category" value="Food and drink"/>
+ <string name="email" value="max@maxloh.com"/>
+ <string name="website" value="www.example.com"/>
+</pbundle_as_map>
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/appinfo/od/all-fields-valid.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/appinfo/od/all-fields-valid.xml
index bce51799c7ff..7aae4a715b79 100644
--- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/appinfo/od/all-fields-valid.xml
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/appinfo/od/all-fields-valid.xml
@@ -1,6 +1,5 @@
<pbundle_as_map name="app_info">
- <boolean name="aps_compliant" value="false"/>
<string name="privacy_policy" value="www.example.com"/>
<string-array name="first_party_endpoints" num="1">
<item value="url1"/>
@@ -9,4 +8,7 @@
<item value="url55"/>
<item value="url56"/>
</string-array>
+ <boolean name="aps_compliant" value="false"/>
+ <string name="developer_id" value="dev1"/>
+ <string name="application_id" value="app1"/>
</pbundle_as_map> \ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/appinfo/od/unrecognized-v1.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/appinfo/od/unrecognized-v1.xml
new file mode 100644
index 000000000000..810078e777fb
--- /dev/null
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/appinfo/od/unrecognized-v1.xml
@@ -0,0 +1,25 @@
+<pbundle_as_map name="app_info">
+ <string name="title" value="beervision"/>
+ <string name="description" value="a beer app"/>
+ <boolean name="contains_ads" value="true"/>
+ <boolean name="obey_aps" value="false"/>
+ <boolean name="ads_fingerprinting" value="false"/>
+ <boolean name="security_fingerprinting" value="false"/>
+ <string name="privacy_policy" value="www.example.com"/>
+ <string-array name="security_endpoints" num="3">
+ <item value="url1"/>
+ <item value="url2"/>
+ <item value="url3"/>
+ </string-array>
+ <string-array name="first_party_endpoints" num="1">
+ <item value="url1"/>
+ </string-array>
+ <string-array name="service_provider_endpoints" num="2">
+ <item value="url55"/>
+ <item value="url56"/>
+ </string-array>
+ <string name="category" value="Food and drink"/>
+ <string name="email" value="max@maxloh.com"/>
+ <string name="website" value="www.example.com"/>
+ <string name="unrecognized" value="www.example.com"/>
+</pbundle_as_map>
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/hr/with-app-info.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/hr/with-app-info.xml
index 2512ca415d55..2c5cf866547a 100644
--- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/hr/with-app-info.xml
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/hr/with-app-info.xml
@@ -2,7 +2,7 @@
<transparency-info>
<app-info
apsCompliant="false"
- privacyPolicy="www.example.com">
+ privacyPolicy="www.example.com" developerId="dev1" applicationId="app1">
<first-party-endpoints>
<item>url1</item>
</first-party-endpoints>
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/hr/with-developer-info.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/hr/with-developer-info.xml
index d16caaea320f..29c88d23abad 100644
--- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/hr/with-developer-info.xml
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/hr/with-developer-info.xml
@@ -1,5 +1,16 @@
<transparency-info>
+ <app-info
+ apsCompliant="false"
+ privacyPolicy="www.example.com" developerId="dev1" applicationId="app1">
+ <first-party-endpoints>
+ <item>url1</item>
+ </first-party-endpoints>
+ <service-provider-endpoints>
+ <item>url55</item>
+ <item>url56</item>
+ </service-provider-endpoints>
+ </app-info>
<developer-info
name="max"
email="max@example.com"
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/od/with-app-info.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/od/with-app-info.xml
index c7bdd97a356c..c46cec1da336 100644
--- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/od/with-app-info.xml
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/od/with-app-info.xml
@@ -1,7 +1,6 @@
<pbundle_as_map name="transparency_info">
<pbundle_as_map name="app_info">
- <boolean name="aps_compliant" value="false"/>
<string name="privacy_policy" value="www.example.com"/>
<string-array name="first_party_endpoints" num="1">
<item value="url1"/>
@@ -10,5 +9,8 @@
<item value="url55"/>
<item value="url56"/>
</string-array>
+ <boolean name="aps_compliant" value="false"/>
+ <string name="developer_id" value="dev1"/>
+ <string name="application_id" value="app1"/>
</pbundle_as_map>
</pbundle_as_map> \ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/od/with-developer-info.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/od/with-developer-info.xml
index d7a4e1a959b7..b5e64b925ca5 100644
--- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/od/with-developer-info.xml
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/od/with-developer-info.xml
@@ -1,5 +1,18 @@
<pbundle_as_map name="transparency_info">
+ <pbundle_as_map name="app_info">
+ <string name="privacy_policy" value="www.example.com"/>
+ <string-array name="first_party_endpoints" num="1">
+ <item value="url1"/>
+ </string-array>
+ <string-array name="service_provider_endpoints" num="2">
+ <item value="url55"/>
+ <item value="url56"/>
+ </string-array>
+ <boolean name="aps_compliant" value="false"/>
+ <string name="developer_id" value="dev1"/>
+ <string name="application_id" value="app1"/>
+ </pbundle_as_map>
<pbundle_as_map name="developer_info">
<string name="name" value="max"/>
<string name="email" value="max@example.com"/>
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/general-v1/od.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/general-v1/od.xml
new file mode 100644
index 000000000000..e8b0c17ecada
--- /dev/null
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/general-v1/od.xml
@@ -0,0 +1,70 @@
+<bundle>
+ <long name="version" value="1"/>
+ <pbundle_as_map name="safety_labels">
+ <pbundle_as_map name="data_labels">
+ <pbundle_as_map name="data_shared">
+ <pbundle_as_map name="location">
+ <pbundle_as_map name="approx_location">
+ <int-array name="purposes" num="1">
+ <item value="1"/>
+ </int-array>
+ <boolean name="is_sharing_optional" value="false"/>
+ <boolean name="ephemeral" value="false"/>
+ </pbundle_as_map>
+ <pbundle_as_map name="precise_location">
+ <int-array name="purposes" num="2">
+ <item value="1"/>
+ <item value="2"/>
+ </int-array>
+ <boolean name="is_sharing_optional" value="true"/>
+ <boolean name="ephemeral" value="true"/>
+ </pbundle_as_map>
+ </pbundle_as_map>
+ </pbundle_as_map>
+ </pbundle_as_map>
+ <pbundle_as_map name="security_labels">
+ <boolean name="is_data_deletable" value="true"/>
+ <boolean name="is_data_encrypted" value="false"/>
+ </pbundle_as_map>
+ <pbundle_as_map name="third_party_verification">
+ <string name="url" value="www.example.com"/>
+ </pbundle_as_map>
+ </pbundle_as_map>
+ <pbundle_as_map name="system_app_safety_label">
+ <string name="url" value="www.example.com"/>
+ </pbundle_as_map>
+ <pbundle_as_map name="transparency_info">
+ <pbundle_as_map name="developer_info">
+ <string name="name" value="max"/>
+ <string name="email" value="max@example.com"/>
+ <string name="address" value="111 blah lane"/>
+ <string name="country_region" value="US"/>
+ <long name="relationship" value="5"/>
+ <string name="website" value="example.com"/>
+ <string name="app_developer_registry_id" value="registry_id"/>
+ </pbundle_as_map>
+ <pbundle_as_map name="app_info">
+ <string name="title" value="beervision"/>
+ <string name="description" value="a beer app"/>
+ <boolean name="contains_ads" value="true"/>
+ <boolean name="obey_aps" value="false"/>
+ <boolean name="ads_fingerprinting" value="false"/>
+ <boolean name="security_fingerprinting" value="false"/>
+ <string name="privacy_policy" value="www.example.com"/>
+ <string-array name="security_endpoints" num="3">
+ <item value="url1"/>
+ <item value="url2"/>
+ <item value="url3"/>
+ </string-array>
+ <string-array name="first_party_endpoints" num="1">
+ <item value="url1"/>
+ </string-array>
+ <string-array name="service_provider_endpoints" num="2">
+ <item value="url55"/>
+ <item value="url56"/>
+ </string-array>
+ <string name="category" value="Food and drink"/>
+ <string name="email" value="max@maxloh.com"/>
+ </pbundle_as_map>
+ </pbundle_as_map>
+</bundle> \ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/general/hr.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/general/hr.xml
index 592307937896..f93298286944 100644
--- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/general/hr.xml
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/general/hr.xml
@@ -1,20 +1,13 @@
-<app-metadata-bundles version="123">
+<app-metadata-bundles version="2">
<safety-labels>
<data-labels>
- <data-shared
- dataType="location_data_type_approx_location"
- isSharingOptional="false"
- purposes="app_functionality" />
- <data-shared
- dataType="location_data_type_precise_location"
- isSharingOptional="true"
- purposes="app_functionality|analytics" />
+ <data-shared dataType="location_data_type_approx_location" isSharingOptional="false" purposes="app_functionality"/>
+ <data-shared dataType="location_data_type_precise_location" isSharingOptional="true" purposes="app_functionality|analytics"/>
</data-labels>
</safety-labels>
- <system-app-safety-label declaration="true">
- </system-app-safety-label>
+ <system-app-safety-label declaration="true"/>
<transparency-info>
- <app-info apsCompliant="false" privacyPolicy="www.example.com">
+ <app-info applicationId="app1" apsCompliant="false" developerId="dev1" privacyPolicy="www.example.com">
<first-party-endpoints>
<item>url1</item>
</first-party-endpoints>
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/general/od.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/general/od.xml
index c24087e483b6..c7def7227a34 100644
--- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/general/od.xml
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/general/od.xml
@@ -1,5 +1,5 @@
<bundle>
- <long name="version" value="123"/>
+ <long name="version" value="2"/>
<pbundle_as_map name="safety_labels">
<pbundle_as_map name="data_labels">
<pbundle_as_map name="data_shared">
@@ -26,7 +26,6 @@
</pbundle_as_map>
<pbundle_as_map name="transparency_info">
<pbundle_as_map name="app_info">
- <boolean name="aps_compliant" value="false"/>
<string name="privacy_policy" value="www.example.com"/>
<string-array name="first_party_endpoints" num="1">
<item value="url1"/>
@@ -35,6 +34,9 @@
<item value="url55"/>
<item value="url56"/>
</string-array>
+ <boolean name="aps_compliant" value="false"/>
+ <string name="developer_id" value="dev1"/>
+ <string name="application_id" value="app1"/>
</pbundle_as_map>
</pbundle_as_map>
</bundle> \ No newline at end of file